mirror of
https://github.com/bolucat/Archive.git
synced 2025-09-26 20:21:35 +08:00
Update On Sun May 26 20:29:40 CEST 2024
This commit is contained in:
1
.github/update.log
vendored
1
.github/update.log
vendored
@@ -658,3 +658,4 @@ Update On Wed May 22 20:31:05 CEST 2024
|
||||
Update On Thu May 23 20:29:12 CEST 2024
|
||||
Update On Fri May 24 20:29:24 CEST 2024
|
||||
Update On Sat May 25 20:28:13 CEST 2024
|
||||
Update On Sun May 26 20:29:29 CEST 2024
|
||||
|
15
clash-nyanpasu/backend/Cargo.lock
generated
15
clash-nyanpasu/backend/Cargo.lock
generated
@@ -932,7 +932,7 @@ dependencies = [
|
||||
"windows-sys 0.52.0",
|
||||
"winreg 0.52.0",
|
||||
"wry",
|
||||
"zip 2.0.0",
|
||||
"zip 2.1.0",
|
||||
"zip-extensions",
|
||||
]
|
||||
|
||||
@@ -5109,18 +5109,18 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "serde"
|
||||
version = "1.0.202"
|
||||
version = "1.0.203"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "226b61a0d411b2ba5ff6d7f73a476ac4f8bb900373459cd00fab8512828ba395"
|
||||
checksum = "7253ab4de971e72fb7be983802300c30b5a7f0c2e56fab8abfc6a214307c0094"
|
||||
dependencies = [
|
||||
"serde_derive",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "serde_derive"
|
||||
version = "1.0.202"
|
||||
version = "1.0.203"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "6048858004bcff69094cd972ed40a32500f153bd3be9f716b2eed2e8217c4838"
|
||||
checksum = "500cbc0ebeb6f46627f50f3f5811ccf6bf00643be300b4c3eabc0ef55dc5b5ba"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
@@ -7833,9 +7833,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "zip"
|
||||
version = "2.0.0"
|
||||
version = "2.1.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "fccb210625924ecbbe92f9bb497d04b167b64fe5540cec75f10b16e0c51ee92b"
|
||||
checksum = "e2568cd0f20e86cd9a7349fe05178f7bd22f22724678448ae5a9bac266df2689"
|
||||
dependencies = [
|
||||
"aes",
|
||||
"arbitrary",
|
||||
@@ -7849,6 +7849,7 @@ dependencies = [
|
||||
"hmac",
|
||||
"indexmap 2.2.6",
|
||||
"lzma-rs",
|
||||
"memchr",
|
||||
"pbkdf2 0.12.2",
|
||||
"rand 0.8.5",
|
||||
"sha1",
|
||||
|
@@ -4,6 +4,7 @@ import {
|
||||
FilterDrama,
|
||||
InsertDriveFile,
|
||||
FiberManualRecord,
|
||||
Terminal,
|
||||
} from "@mui/icons-material";
|
||||
import LoadingButton from "@mui/lab/LoadingButton";
|
||||
import {
|
||||
@@ -14,7 +15,8 @@ import {
|
||||
Menu,
|
||||
MenuItem,
|
||||
useTheme,
|
||||
lighten,
|
||||
Button,
|
||||
alpha,
|
||||
} from "@mui/material";
|
||||
import { Profile, useClash } from "@nyanpasu/interface";
|
||||
import dayjs from "dayjs";
|
||||
@@ -27,11 +29,15 @@ import { useLockFn, useSetState } from "ahooks";
|
||||
export interface ProfileItemProps {
|
||||
item: Profile.Item;
|
||||
selected?: boolean;
|
||||
onClickChains: (item: Profile.Item) => void;
|
||||
chainsSelected?: boolean;
|
||||
}
|
||||
|
||||
export const ProfileItem = memo(function ProfileItem({
|
||||
item,
|
||||
selected,
|
||||
onClickChains,
|
||||
chainsSelected,
|
||||
}: ProfileItemProps) {
|
||||
const { t } = useTranslation();
|
||||
|
||||
@@ -141,6 +147,7 @@ export const ProfileItem = memo(function ProfileItem({
|
||||
const menuMapping = {
|
||||
Select: () => handleSelect(),
|
||||
Edit: () => setOpen(true),
|
||||
Chains: () => onClickChains(item),
|
||||
"Open File": () => viewProfile(item.uid),
|
||||
Update: () => handleUpdate(),
|
||||
"Update(Proxy)": () => handleUpdate(true),
|
||||
@@ -156,7 +163,7 @@ export const ProfileItem = memo(function ProfileItem({
|
||||
sx={{
|
||||
borderRadius: 6,
|
||||
backgroundColor: selected
|
||||
? lighten(palette.primary.main, 0.9)
|
||||
? alpha(palette.primary.main, 0.2)
|
||||
: undefined,
|
||||
}}
|
||||
>
|
||||
@@ -201,6 +208,16 @@ export const ProfileItem = memo(function ProfileItem({
|
||||
)}
|
||||
|
||||
<div className="flex gap-2 justify-end">
|
||||
<Button
|
||||
className="!mr-auto"
|
||||
size="small"
|
||||
variant={chainsSelected ? "contained" : "outlined"}
|
||||
startIcon={<Terminal />}
|
||||
onClick={() => onClickChains(item)}
|
||||
>
|
||||
Chains
|
||||
</Button>
|
||||
|
||||
{isRemote && (
|
||||
<LoadingButton
|
||||
size="small"
|
||||
|
@@ -1,6 +1,6 @@
|
||||
import { forwardRef, useImperativeHandle, useRef } from "react";
|
||||
import { forwardRef, useEffect, useImperativeHandle, useRef } from "react";
|
||||
import { monaco } from "@/services/monaco";
|
||||
import { useDebounceEffect } from "ahooks";
|
||||
import { useDebounceEffect, useUpdateEffect } from "ahooks";
|
||||
import { themeMode } from "@/store";
|
||||
import { useAtomValue } from "jotai";
|
||||
|
||||
@@ -53,5 +53,13 @@ export const ProfileMonacoView = forwardRef(function ProfileMonacoView(
|
||||
getValue: () => instanceRef.current?.getValue(),
|
||||
}));
|
||||
|
||||
useUpdateEffect(() => {
|
||||
if (!language) return;
|
||||
|
||||
monaco.editor.setModelLanguage(instanceRef.current!.getModel()!, language);
|
||||
|
||||
console.log(language, instanceRef.current?.getModel()?.getLanguageId());
|
||||
}, [language]);
|
||||
|
||||
return open && <div ref={monacoRef} className={className} />;
|
||||
});
|
||||
|
@@ -0,0 +1,200 @@
|
||||
import { Add, Close, Edit, RamenDining, Terminal } from "@mui/icons-material";
|
||||
import {
|
||||
Divider,
|
||||
ListItemButton,
|
||||
ListItemIcon,
|
||||
ListItemText,
|
||||
IconButton,
|
||||
List,
|
||||
useTheme,
|
||||
alpha,
|
||||
} from "@mui/material";
|
||||
import { Profile, useClash } from "@nyanpasu/interface";
|
||||
import { useState } from "react";
|
||||
import { filterProfiles } from "./utils";
|
||||
import { useLockFn } from "ahooks";
|
||||
import { Expand, ExpandMore } from "@nyanpasu/ui";
|
||||
import { isEmpty } from "lodash-es";
|
||||
import { ScriptDialog } from "./script-dialog";
|
||||
import { VList } from "virtua";
|
||||
|
||||
export interface ProfileSideProps {
|
||||
profile?: Profile.Item;
|
||||
global?: boolean;
|
||||
onClose: () => void;
|
||||
}
|
||||
|
||||
export const ProfileSide = ({ profile, global, onClose }: ProfileSideProps) => {
|
||||
const { palette } = useTheme();
|
||||
|
||||
const [open, setOpen] = useState(false);
|
||||
|
||||
const { getProfiles, setProfilesConfig, getRuntimeLogs, setProfiles } =
|
||||
useClash();
|
||||
|
||||
const { scripts } = filterProfiles(getProfiles.data?.items);
|
||||
|
||||
const handleChainClick = useLockFn(async (uid: string) => {
|
||||
const chains = global
|
||||
? getProfiles.data?.chain ?? []
|
||||
: profile?.chains ?? [];
|
||||
|
||||
const updatedChains = chains.includes(uid)
|
||||
? chains.filter((chain) => chain !== uid)
|
||||
: [...chains, uid];
|
||||
|
||||
if (global) {
|
||||
await setProfilesConfig({ chain: updatedChains });
|
||||
} else {
|
||||
await setProfiles(uid, { chains: updatedChains });
|
||||
}
|
||||
});
|
||||
|
||||
const [item, setItem] = useState<Profile.Item>();
|
||||
|
||||
const handleEditChain = async (item: Profile.Item) => {
|
||||
setItem(item);
|
||||
setOpen(true);
|
||||
};
|
||||
|
||||
const [expand, setExpand] = useState(false);
|
||||
|
||||
return (
|
||||
<div className="relative h-full">
|
||||
<div className="flex-col gap-2">
|
||||
<div className="p-4 pr-2 flex justify-between items-start">
|
||||
<div>
|
||||
<div className="text-xl font-bold">Proxy Chains</div>
|
||||
|
||||
<div className="truncate">
|
||||
{global ? "Global Chain" : profile?.name}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<IconButton onClick={onClose}>
|
||||
<Close />
|
||||
</IconButton>
|
||||
</div>
|
||||
|
||||
<List className="!pl-2 !pr-2 overflow-auto" disablePadding>
|
||||
{scripts?.map((item, index) => {
|
||||
const selected = global
|
||||
? getProfiles.data?.chain?.includes(item.uid)
|
||||
: profile?.chains?.includes(item.uid);
|
||||
|
||||
return (
|
||||
<ListItemButton
|
||||
key={index}
|
||||
className="!mt-2 !mb-2"
|
||||
sx={{
|
||||
backgroundColor: selected
|
||||
? alpha(palette.primary.main, 0.3)
|
||||
: alpha(palette.grey[100], 0.1),
|
||||
borderRadius: 4,
|
||||
|
||||
"&:hover": {
|
||||
backgroundColor: selected
|
||||
? alpha(palette.primary.main, 0.5)
|
||||
: undefined,
|
||||
},
|
||||
}}
|
||||
onClick={() => handleChainClick(item.uid)}
|
||||
>
|
||||
<ListItemText primary={item.name} secondary={item.desc} />
|
||||
|
||||
<IconButton
|
||||
edge="end"
|
||||
color="primary"
|
||||
onClick={(e) => {
|
||||
e.preventDefault();
|
||||
e.stopPropagation();
|
||||
handleEditChain(item);
|
||||
}}
|
||||
>
|
||||
<Edit />
|
||||
</IconButton>
|
||||
</ListItemButton>
|
||||
);
|
||||
})}
|
||||
|
||||
<ListItemButton
|
||||
className="!mt-2!mb-2"
|
||||
sx={{
|
||||
backgroundColor: alpha(palette.grey[100], 0.1),
|
||||
borderRadius: 4,
|
||||
}}
|
||||
onClick={() => setOpen(true)}
|
||||
>
|
||||
<ListItemIcon>
|
||||
<Add color="primary" />
|
||||
</ListItemIcon>
|
||||
|
||||
<ListItemText primary="New Chian" />
|
||||
</ListItemButton>
|
||||
</List>
|
||||
</div>
|
||||
|
||||
<ScriptDialog
|
||||
open={open}
|
||||
item={item}
|
||||
onClose={() => {
|
||||
setOpen(false);
|
||||
setItem(undefined);
|
||||
}}
|
||||
/>
|
||||
|
||||
<div className="absolute bottom-0 z-10 w-full">
|
||||
<Divider />
|
||||
|
||||
<div className="p-1 pl-4 flex justify-between items-center">
|
||||
<div className="flex items-center gap-2">
|
||||
<Terminal />
|
||||
|
||||
<span>Console</span>
|
||||
</div>
|
||||
|
||||
<ExpandMore
|
||||
size="small"
|
||||
reverse
|
||||
expand={expand}
|
||||
onClick={() => setExpand(!expand)}
|
||||
/>
|
||||
</div>
|
||||
|
||||
<Expand open={expand}>
|
||||
<Divider />
|
||||
|
||||
<VList className="flex flex-col gap-2 p-2 overflow-auto min-h-48 max-h-48">
|
||||
{!isEmpty(getRuntimeLogs.data) ? (
|
||||
Object.entries(getRuntimeLogs.data).map(([uid, content]) => {
|
||||
return content.map((item, index) => {
|
||||
const name = scripts?.find(
|
||||
(script) => script.uid === uid,
|
||||
)?.name;
|
||||
|
||||
return (
|
||||
<>
|
||||
{index !== 0 && <Divider />}
|
||||
|
||||
<div key={uid + index} className="w-full font-mono">
|
||||
<span className="text-red-500">[{name}]: </span>
|
||||
<span>{item}</span>
|
||||
</div>
|
||||
</>
|
||||
);
|
||||
});
|
||||
})
|
||||
) : (
|
||||
<div className="w-full h-full min-h-48 flex flex-col justify-center items-center">
|
||||
<RamenDining className="!size-10" />
|
||||
<p>No Log</p>
|
||||
</div>
|
||||
)}
|
||||
</VList>
|
||||
</Expand>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default ProfileSide;
|
@@ -0,0 +1,199 @@
|
||||
import { Divider } from "@mui/material";
|
||||
import { BaseDialog, BaseDialogProps } from "@nyanpasu/ui";
|
||||
import { useRef } from "react";
|
||||
import { useAsyncEffect, useReactive } from "ahooks";
|
||||
import { Profile, useClash } from "@nyanpasu/interface";
|
||||
import { ProfileMonacoView, ProfileMonacoViewRef } from "./profile-monaco-view";
|
||||
import { SelectElement, TextFieldElement, useForm } from "react-hook-form-mui";
|
||||
import { useTranslation } from "react-i18next";
|
||||
import { isEqual } from "lodash-es";
|
||||
|
||||
export interface ScriptDialogProps extends Omit<BaseDialogProps, "title"> {
|
||||
open: boolean;
|
||||
onClose: () => void;
|
||||
item?: Profile.Item;
|
||||
}
|
||||
|
||||
export const ScriptDialog = ({
|
||||
open,
|
||||
item,
|
||||
onClose,
|
||||
...props
|
||||
}: ScriptDialogProps) => {
|
||||
const { t } = useTranslation();
|
||||
|
||||
const { getProfileFile, setProfileFile, createProfile, setProfiles } =
|
||||
useClash();
|
||||
|
||||
const optionTypeMapping = [
|
||||
{
|
||||
id: "js",
|
||||
value: { script: "javascript" },
|
||||
language: "javascript",
|
||||
label: t("JavaScript"),
|
||||
},
|
||||
{
|
||||
id: "lua",
|
||||
value: { script: "lua" },
|
||||
language: "lua",
|
||||
label: t("LuaScript"),
|
||||
},
|
||||
{
|
||||
id: "merge",
|
||||
value: "merge",
|
||||
language: "yaml",
|
||||
label: t("Merge"),
|
||||
},
|
||||
];
|
||||
|
||||
const preprocessing = () => {
|
||||
const result = optionTypeMapping.find((option) =>
|
||||
isEqual(option.value, item?.type),
|
||||
);
|
||||
|
||||
return { ...item, type: result?.id } as Profile.Item;
|
||||
};
|
||||
|
||||
const { control, watch, handleSubmit, reset } = useForm<Profile.Item>({
|
||||
defaultValues: item
|
||||
? preprocessing()
|
||||
: {
|
||||
type: "merge",
|
||||
chains: [],
|
||||
name: "New Script",
|
||||
desc: "",
|
||||
},
|
||||
});
|
||||
|
||||
const profileMonacoViewRef = useRef<ProfileMonacoViewRef>(null);
|
||||
|
||||
const editor = useReactive({
|
||||
value: "",
|
||||
language: "javascript",
|
||||
});
|
||||
|
||||
const handleTypeChange = () => {
|
||||
const language = optionTypeMapping.find((option) =>
|
||||
isEqual(option.id, watch("type")),
|
||||
)?.language;
|
||||
|
||||
if (language) {
|
||||
editor.language = language;
|
||||
}
|
||||
};
|
||||
|
||||
const isEdit = Boolean(item);
|
||||
|
||||
const commonProps = {
|
||||
autoComplete: "off",
|
||||
autoCorrect: "off",
|
||||
fullWidth: true,
|
||||
};
|
||||
|
||||
const onSubmit = handleSubmit(async (form) => {
|
||||
const value = profileMonacoViewRef.current?.getValue() || "";
|
||||
|
||||
const type = optionTypeMapping.find((option) =>
|
||||
isEqual(option.id, form.type),
|
||||
)?.value;
|
||||
|
||||
const data = {
|
||||
...form,
|
||||
type,
|
||||
} as Profile.Item;
|
||||
|
||||
try {
|
||||
if (isEdit) {
|
||||
await setProfiles(data.uid, data);
|
||||
|
||||
await setProfileFile(data.uid, value);
|
||||
} else {
|
||||
await createProfile(data, value);
|
||||
}
|
||||
|
||||
setTimeout(() => reset(), 300);
|
||||
|
||||
onClose();
|
||||
} finally {
|
||||
}
|
||||
});
|
||||
|
||||
useAsyncEffect(async () => {
|
||||
editor.value = await getProfileFile(item?.uid);
|
||||
|
||||
if (item) {
|
||||
reset(item);
|
||||
} else {
|
||||
reset();
|
||||
}
|
||||
}, [open]);
|
||||
|
||||
return (
|
||||
<BaseDialog
|
||||
title={isEdit ? "Edit Script" : "New Script"}
|
||||
open={open}
|
||||
onClose={() => onClose()}
|
||||
onOk={onSubmit}
|
||||
divider
|
||||
sx={{
|
||||
" .MuiDialog-paper": {
|
||||
maxWidth: "90vw",
|
||||
maxHeight: "90vh",
|
||||
},
|
||||
}}
|
||||
contentSx={{
|
||||
overflow: "auto",
|
||||
width: "90vw",
|
||||
height: "90vh",
|
||||
padding: 0,
|
||||
}}
|
||||
{...props}
|
||||
>
|
||||
<div className="flex h-full">
|
||||
<div className="pt-4 pb-4 overflow-auto">
|
||||
<div className="flex flex-col gap-4 pl-4 pr-4 pb-4">
|
||||
{!isEdit && (
|
||||
<SelectElement
|
||||
label={t("Type")}
|
||||
name="type"
|
||||
control={control}
|
||||
{...commonProps}
|
||||
size="small"
|
||||
required
|
||||
options={optionTypeMapping}
|
||||
onChange={() => handleTypeChange()}
|
||||
/>
|
||||
)}
|
||||
|
||||
<TextFieldElement
|
||||
label={t("Name")}
|
||||
name="name"
|
||||
control={control}
|
||||
{...commonProps}
|
||||
size="small"
|
||||
required
|
||||
/>
|
||||
|
||||
<TextFieldElement
|
||||
label={t("Descriptions")}
|
||||
name="desc"
|
||||
control={control}
|
||||
{...commonProps}
|
||||
size="small"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<Divider orientation="vertical" />
|
||||
|
||||
<ProfileMonacoView
|
||||
className="w-full"
|
||||
ref={profileMonacoViewRef}
|
||||
open={open}
|
||||
value={editor.value}
|
||||
language={editor.language}
|
||||
/>
|
||||
</div>
|
||||
</BaseDialog>
|
||||
);
|
||||
};
|
@@ -13,9 +13,12 @@ import { proxyGroupAtom, proxyGroupSortAtom } from "@/store";
|
||||
import { CSSProperties, memo, useEffect, useMemo, useState } from "react";
|
||||
import { classNames } from "@/utils";
|
||||
import { VList } from "virtua";
|
||||
import { AnimatePresence, motion } from "framer-motion";
|
||||
|
||||
type History = Clash.Proxy["history"];
|
||||
|
||||
type RenderClashProxy = Clash.Proxy<string> & { renderLayoutKey: string };
|
||||
|
||||
const filterDelay = (history?: History): number => {
|
||||
if (!history || history.length == 0) {
|
||||
return 0;
|
||||
@@ -218,15 +221,36 @@ export const NodeList = () => {
|
||||
default: 4,
|
||||
});
|
||||
|
||||
const [renderList, setRenderList] = useState<Clash.Proxy<string>[][]>([]);
|
||||
const [renderList, setRenderList] = useState<RenderClashProxy[][]>([]);
|
||||
|
||||
useEffect(() => {
|
||||
if (!group?.all) return;
|
||||
|
||||
const list = group?.all?.reduce<Clash.Proxy<string>[][]>(
|
||||
const nodeNames: string[] = [];
|
||||
|
||||
const list = group?.all?.reduce<RenderClashProxy[][]>(
|
||||
(result, value, index) => {
|
||||
if (index % column === 0) result.push([]);
|
||||
result[Math.floor(index / column)].push(value);
|
||||
const getKey = () => {
|
||||
const filter = nodeNames.filter((i) => i === value.name);
|
||||
|
||||
if (filter.length === 0) {
|
||||
return value.name;
|
||||
} else {
|
||||
return `${value.name}-${filter.length}`;
|
||||
}
|
||||
};
|
||||
|
||||
if (index % column === 0) {
|
||||
result.push([]);
|
||||
}
|
||||
|
||||
result[Math.floor(index / column)].push({
|
||||
...value,
|
||||
renderLayoutKey: getKey(),
|
||||
});
|
||||
|
||||
nodeNames.push(value.name);
|
||||
|
||||
return result;
|
||||
},
|
||||
[],
|
||||
@@ -240,35 +264,42 @@ export const NodeList = () => {
|
||||
};
|
||||
|
||||
return (
|
||||
<VList style={{ flex: 1 }} className="p-2">
|
||||
{renderList?.map((node, index) => {
|
||||
return (
|
||||
<div key={index} className="flex">
|
||||
{node.map((render, index) => {
|
||||
return (
|
||||
<div
|
||||
key={index}
|
||||
className="relative p-2"
|
||||
style={{
|
||||
flex: 1 / column,
|
||||
width: `calc(100% / ${column})`,
|
||||
}}
|
||||
>
|
||||
<NodeCard
|
||||
node={render}
|
||||
now={group?.now}
|
||||
disabled={group?.type !== "Selector"}
|
||||
onClick={() => hendleClick(render.name)}
|
||||
onClickDelay={async () => {
|
||||
await updateProxiesDelay(render.name);
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
})}
|
||||
</div>
|
||||
);
|
||||
})}
|
||||
</VList>
|
||||
<AnimatePresence initial={false}>
|
||||
<VList style={{ flex: 1 }} className="p-2">
|
||||
{renderList?.map((node, index) => {
|
||||
return (
|
||||
<div
|
||||
key={index}
|
||||
className="grid gap-2 pb-2"
|
||||
style={{ gridTemplateColumns: `repeat(${column} , 1fr)` }}
|
||||
>
|
||||
{node.map((render) => {
|
||||
return (
|
||||
<motion.div
|
||||
key={render.name}
|
||||
layoutId={`node-${render.renderLayoutKey}`}
|
||||
className="relative overflow-hidden"
|
||||
layout="position"
|
||||
initial={false}
|
||||
animate="center"
|
||||
exit="exit"
|
||||
>
|
||||
<NodeCard
|
||||
node={render}
|
||||
now={group?.now}
|
||||
disabled={group?.type !== "Selector"}
|
||||
onClick={() => hendleClick(render.name)}
|
||||
onClickDelay={async () => {
|
||||
await updateProxiesDelay(render.name);
|
||||
}}
|
||||
/>
|
||||
</motion.div>
|
||||
);
|
||||
})}
|
||||
</div>
|
||||
);
|
||||
})}
|
||||
</VList>
|
||||
</AnimatePresence>
|
||||
);
|
||||
};
|
||||
|
@@ -1,48 +1,102 @@
|
||||
import { Button, alpha, useTheme } from "@mui/material";
|
||||
import { useNyanpasu } from "@nyanpasu/interface";
|
||||
import { Button } from "@mui/material";
|
||||
import { Profile, useClash } from "@nyanpasu/interface";
|
||||
import { SidePage } from "@nyanpasu/ui";
|
||||
import { useEffect, useState } from "react";
|
||||
import { useTranslation } from "react-i18next";
|
||||
import Grid from "@mui/material/Unstable_Grid2";
|
||||
import { Add } from "@mui/icons-material";
|
||||
import ProfileItem from "@/components/profiles/profile-item";
|
||||
import ProfileSide from "@/components/profiles/profile-side";
|
||||
import { filterProfiles } from "@/components/profiles/utils";
|
||||
import NewProfileButton from "@/components/profiles/new-profile-button";
|
||||
import { QuickImport } from "@/components/profiles/quick-import";
|
||||
import Masonry from "@mui/lab/Masonry";
|
||||
|
||||
export const ProfilePage = () => {
|
||||
const { t } = useTranslation();
|
||||
|
||||
const { getProfiles } = useNyanpasu();
|
||||
const { getProfiles } = useClash();
|
||||
|
||||
const { profiles } = filterProfiles(getProfiles.data?.items);
|
||||
const { profiles, scripts } = filterProfiles(getProfiles.data?.items);
|
||||
|
||||
const { palette } = useTheme();
|
||||
useEffect(() => {
|
||||
console.log("getProfiles.data:", getProfiles.data);
|
||||
console.log("profiles:", profiles);
|
||||
console.log("scripts:", scripts);
|
||||
}, [getProfiles.data?.items]);
|
||||
|
||||
const [globalChain, setGlobalChain] = useState(false);
|
||||
|
||||
const handleGlobalChainClick = () => {
|
||||
setChainsSelected(undefined);
|
||||
setGlobalChain(!globalChain);
|
||||
};
|
||||
|
||||
const [chainsSelected, setChainsSelected] = useState<Profile.Item>();
|
||||
|
||||
const onClickChains = (profile: Profile.Item) => {
|
||||
setGlobalChain(false);
|
||||
|
||||
if (chainsSelected?.uid == profile.uid) {
|
||||
setChainsSelected(undefined);
|
||||
} else {
|
||||
setChainsSelected(profile);
|
||||
}
|
||||
};
|
||||
|
||||
const handleSideClose = () => {
|
||||
setChainsSelected(undefined);
|
||||
setGlobalChain(false);
|
||||
};
|
||||
|
||||
return (
|
||||
<SidePage title={t("Profiles")} flexReverse>
|
||||
<div className="p-6">
|
||||
<Grid container spacing={2}>
|
||||
{profiles?.map((item, index) => {
|
||||
return (
|
||||
<Grid key={index} xs={12} sm={6} md={6} xl={4}>
|
||||
<ProfileItem item={item} />
|
||||
</Grid>
|
||||
);
|
||||
})}
|
||||
</Grid>
|
||||
<SidePage
|
||||
title={t("Profiles")}
|
||||
flexReverse
|
||||
header={
|
||||
<div>
|
||||
<Button
|
||||
variant={globalChain ? "contained" : "outlined"}
|
||||
onClick={handleGlobalChainClick}
|
||||
>
|
||||
Global Chain
|
||||
</Button>
|
||||
</div>
|
||||
}
|
||||
sideClassName="!overflow-visible"
|
||||
side={
|
||||
(globalChain || chainsSelected) && (
|
||||
<ProfileSide
|
||||
profile={chainsSelected}
|
||||
global={globalChain}
|
||||
onClose={handleSideClose}
|
||||
/>
|
||||
)
|
||||
}
|
||||
>
|
||||
<div className="flex flex-col gap-4 p-6">
|
||||
<QuickImport />
|
||||
|
||||
{profiles && (
|
||||
<Masonry
|
||||
columns={{ xs: 1, sm: 1, md: 2, xl: 3 }}
|
||||
spacing={2}
|
||||
sx={{ width: "calc(100% + 24px)" }}
|
||||
>
|
||||
{profiles.map((item, index) => {
|
||||
return (
|
||||
<ProfileItem
|
||||
key={index}
|
||||
item={item}
|
||||
onClickChains={onClickChains}
|
||||
selected={getProfiles.data?.current == item.uid}
|
||||
chainsSelected={chainsSelected?.uid == item.uid}
|
||||
/>
|
||||
);
|
||||
})}
|
||||
</Masonry>
|
||||
)}
|
||||
</div>
|
||||
|
||||
<Button
|
||||
className="size-16 backdrop-blur !rounded-2xl !absolute z-10 bottom-8 right-8"
|
||||
sx={{
|
||||
boxShadow: 8,
|
||||
backgroundColor: alpha(palette.primary.main, 0.3),
|
||||
|
||||
"&:hover": {
|
||||
backgroundColor: alpha(palette.primary.main, 0.45),
|
||||
},
|
||||
}}
|
||||
>
|
||||
<Add className="!size-8 absolute" />
|
||||
</Button>
|
||||
<NewProfileButton />
|
||||
</SidePage>
|
||||
);
|
||||
};
|
||||
|
@@ -4,6 +4,7 @@ import useTheme from "@mui/material/styles/useTheme";
|
||||
|
||||
interface ExpandMoreProps extends IconButtonProps {
|
||||
expand: boolean;
|
||||
reverse?: boolean;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -15,14 +16,20 @@ interface ExpandMoreProps extends IconButtonProps {
|
||||
* @author keiko233 <i@elaina.moe>
|
||||
* @copyright LibNyanpasu org. 2024
|
||||
*/
|
||||
export const ExpandMore = ({ expand, ...props }: ExpandMoreProps) => {
|
||||
export const ExpandMore = ({ expand, reverse, ...props }: ExpandMoreProps) => {
|
||||
const { transitions } = useTheme();
|
||||
|
||||
return (
|
||||
<IconButton {...props}>
|
||||
<ExpandMoreIcon
|
||||
sx={{
|
||||
transform: !expand ? "rotate(0deg)" : "rotate(180deg)",
|
||||
transform: !expand
|
||||
? reverse
|
||||
? "rotate(180deg)"
|
||||
: "rotate(0deg)"
|
||||
: reverse
|
||||
? "rotate(0deg)"
|
||||
: "rotate(180deg)",
|
||||
marginLeft: "auto",
|
||||
transition: transitions.create("transform", {
|
||||
duration: transitions.duration.shortest,
|
||||
|
@@ -12,6 +12,7 @@ interface Props {
|
||||
children?: ReactNode;
|
||||
sideBar?: ReactNode;
|
||||
side?: ReactNode;
|
||||
sideClassName?: string;
|
||||
toolBar?: ReactNode;
|
||||
noChildrenScroll?: boolean;
|
||||
flexReverse?: boolean;
|
||||
@@ -43,6 +44,7 @@ export const SidePage: FC<Props> = ({
|
||||
children,
|
||||
sideBar,
|
||||
side,
|
||||
sideClassName,
|
||||
toolBar,
|
||||
noChildrenScroll,
|
||||
flexReverse,
|
||||
@@ -82,7 +84,7 @@ export const SidePage: FC<Props> = ({
|
||||
{sideBar && <div>{sideBar}</div>}
|
||||
|
||||
<div className={style["LeftContainer-Content"]}>
|
||||
<section>{side}</section>
|
||||
<section className={sideClassName}>{side}</section>
|
||||
</div>
|
||||
</motion.div>
|
||||
|
||||
|
@@ -1,3 +1,25 @@
|
||||
## v1.6.4
|
||||
|
||||
### Features
|
||||
|
||||
- 系统代理支持 PAC 模式
|
||||
- 允许关闭不使用的端口
|
||||
- 使用新的应用图标
|
||||
- MacOS 支持切换托盘图标单色/彩色模式
|
||||
- CSS 注入支持通过编辑器编辑
|
||||
- 优化代理组列表性能
|
||||
- 优化流量图显性能
|
||||
- 支持波斯语
|
||||
|
||||
### Bugs Fixes
|
||||
|
||||
- Kill 内核后 Tun 开启缓慢的问题
|
||||
- 代理绕过为空时使用默认值
|
||||
- 无法读取剪切板内容
|
||||
- Windows 下覆盖安装无法内核占用问题
|
||||
|
||||
---
|
||||
|
||||
## v1.6.2
|
||||
|
||||
### Features
|
||||
@@ -16,6 +38,8 @@
|
||||
- Linux 下与 N 卡的兼容性问题
|
||||
- 修改 Tun 设置不立即生效
|
||||
|
||||
---
|
||||
|
||||
## v1.6.1
|
||||
|
||||
### Features
|
||||
|
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "clash-verge",
|
||||
"version": "1.6.2",
|
||||
"version": "1.6.4",
|
||||
"license": "GPL-3.0-only",
|
||||
"scripts": {
|
||||
"dev": "tauri dev",
|
||||
@@ -32,7 +32,6 @@
|
||||
"@types/json-schema": "^7.0.15",
|
||||
"ahooks": "^3.7.11",
|
||||
"axios": "^1.6.8",
|
||||
"axios-tauri-api-adapter": "^0.2.1",
|
||||
"dayjs": "1.11.5",
|
||||
"i18next": "^23.11.3",
|
||||
"lodash-es": "^4.17.21",
|
||||
|
63
clash-verge-rev/pnpm-lock.yaml
generated
63
clash-verge-rev/pnpm-lock.yaml
generated
@@ -49,9 +49,6 @@ importers:
|
||||
axios:
|
||||
specifier: ^1.6.8
|
||||
version: 1.6.8
|
||||
axios-tauri-api-adapter:
|
||||
specifier: ^0.2.1
|
||||
version: 0.2.1
|
||||
dayjs:
|
||||
specifier: 1.11.5
|
||||
version: 1.11.5
|
||||
@@ -1605,13 +1602,6 @@ packages:
|
||||
integrity: sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==,
|
||||
}
|
||||
|
||||
axios-tauri-api-adapter@0.2.1:
|
||||
resolution:
|
||||
{
|
||||
integrity: sha512-XuC6rDl8yOUrctN1nUe5fngPhmq+zhkUvKZVRCUOrlSn5UdLYH0OjrLJl7h8DQdxcAzZw0Oiw+PQFNOBuL42hg==,
|
||||
}
|
||||
engines: { node: ">=16", pnpm: ">=7" }
|
||||
|
||||
axios@1.6.8:
|
||||
resolution:
|
||||
{
|
||||
@@ -1659,12 +1649,6 @@ packages:
|
||||
engines: { node: ^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7 }
|
||||
hasBin: true
|
||||
|
||||
build-url-ts@6.1.7:
|
||||
resolution:
|
||||
{
|
||||
integrity: sha512-KU8hfHxEpBTvoJA4XLiL88JiJN6U0SIVtnXKMSKgxf2T+bP3tDlzd/WIl/dthi+01YXeS49yUxkL3JXyqPdIAw==,
|
||||
}
|
||||
|
||||
callsites@3.1.0:
|
||||
resolution:
|
||||
{
|
||||
@@ -2133,12 +2117,6 @@ packages:
|
||||
integrity: sha512-/sXbVCWayk6GDVg3ctOX6nxaVj7So40FcFAnWlWGNAB1LpYKcV5Cd10APjPjW80O7zYW2MsjBV4zZ7IZO5fVow==,
|
||||
}
|
||||
|
||||
http-status-codes@2.3.0:
|
||||
resolution:
|
||||
{
|
||||
integrity: sha512-RJ8XvFvpPM/Dmc5SV+dC4y5PCeOhT3x1Hq0NU3rjGeg5a/CqlhZ7uudknPwZFz4aeAXDcbAyaeP7GAo9lvngtA==,
|
||||
}
|
||||
|
||||
https-proxy-agent@5.0.1:
|
||||
resolution:
|
||||
{
|
||||
@@ -2913,12 +2891,6 @@ packages:
|
||||
integrity: sha512-LwZy+p3SFs1Pytd/jYct4wpv49HiYCqd9Rlc5ZVdk0V+8Yzv6jR5Blk3TRmPL1ft69TxP0IMZGJ+WPFU2BFhww==,
|
||||
}
|
||||
|
||||
querystringify@2.2.0:
|
||||
resolution:
|
||||
{
|
||||
integrity: sha512-FIqgj2EUvTa7R50u0rGsyTftzjYmv/a3hO345bZNrqabNqjtgiDMgmo4mkUjd+nzU5oF3dClKqFIPUKybUyqoQ==,
|
||||
}
|
||||
|
||||
react-dom@18.3.1:
|
||||
resolution:
|
||||
{
|
||||
@@ -3080,12 +3052,6 @@ packages:
|
||||
integrity: sha512-z3tJrAs2kIs1AqIIy6pzHmAHlF1hWQ+OdY4/hv+Wxe35EhyLKcajL33iUEn3ScxtFox9nUvRufR/Zre8Q08H/g==,
|
||||
}
|
||||
|
||||
requires-port@1.0.0:
|
||||
resolution:
|
||||
{
|
||||
integrity: sha512-KigOCHcocU3XODJxsu8i/j8T9tzT4adHiecwORRQ0ZZFcp7ahwXuRU1m+yuO90C5ZUyGeGfocHDI14M3L3yDAQ==,
|
||||
}
|
||||
|
||||
reselect@4.1.8:
|
||||
resolution:
|
||||
{
|
||||
@@ -3390,12 +3356,6 @@ packages:
|
||||
peerDependencies:
|
||||
browserslist: ">= 4.21.0"
|
||||
|
||||
url-parse@1.5.10:
|
||||
resolution:
|
||||
{
|
||||
integrity: sha512-WypcfiRhfeUP9vvF0j6rw0J3hrWrw6iZv3+22h6iRMJ/8z1Tj6XfLP4DsUix5MhMPnXpiHDoKyoZ/bdCkwBCiQ==,
|
||||
}
|
||||
|
||||
vfile-message@4.0.2:
|
||||
resolution:
|
||||
{
|
||||
@@ -4455,16 +4415,6 @@ snapshots:
|
||||
|
||||
asynckit@0.4.0: {}
|
||||
|
||||
axios-tauri-api-adapter@0.2.1:
|
||||
dependencies:
|
||||
"@tauri-apps/api": 1.5.4
|
||||
axios: 1.6.8
|
||||
build-url-ts: 6.1.7
|
||||
http-status-codes: 2.3.0
|
||||
url-parse: 1.5.10
|
||||
transitivePeerDependencies:
|
||||
- debug
|
||||
|
||||
axios@1.6.8:
|
||||
dependencies:
|
||||
follow-redirects: 1.15.6
|
||||
@@ -4496,8 +4446,6 @@ snapshots:
|
||||
node-releases: 2.0.14
|
||||
update-browserslist-db: 1.0.15(browserslist@4.23.0)
|
||||
|
||||
build-url-ts@6.1.7: {}
|
||||
|
||||
callsites@3.1.0: {}
|
||||
|
||||
camelcase@6.3.0: {}
|
||||
@@ -4774,8 +4722,6 @@ snapshots:
|
||||
|
||||
html-url-attributes@3.0.0: {}
|
||||
|
||||
http-status-codes@2.3.0: {}
|
||||
|
||||
https-proxy-agent@5.0.1:
|
||||
dependencies:
|
||||
agent-base: 6.0.2
|
||||
@@ -5293,8 +5239,6 @@ snapshots:
|
||||
end-of-stream: 1.4.4
|
||||
once: 1.4.0
|
||||
|
||||
querystringify@2.2.0: {}
|
||||
|
||||
react-dom@18.3.1(react@18.3.1):
|
||||
dependencies:
|
||||
loose-envify: 1.4.0
|
||||
@@ -5404,8 +5348,6 @@ snapshots:
|
||||
unified: 11.0.4
|
||||
vfile: 6.0.1
|
||||
|
||||
requires-port@1.0.0: {}
|
||||
|
||||
reselect@4.1.8: {}
|
||||
|
||||
resize-observer-polyfill@1.5.1: {}
|
||||
@@ -5581,11 +5523,6 @@ snapshots:
|
||||
escalade: 3.1.2
|
||||
picocolors: 1.0.0
|
||||
|
||||
url-parse@1.5.10:
|
||||
dependencies:
|
||||
querystringify: 2.2.0
|
||||
requires-port: 1.0.0
|
||||
|
||||
vfile-message@4.0.2:
|
||||
dependencies:
|
||||
"@types/unist": 3.0.2
|
||||
|
4
clash-verge-rev/src-tauri/Cargo.lock
generated
4
clash-verge-rev/src-tauri/Cargo.lock
generated
@@ -788,7 +788,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "clash-verge"
|
||||
version = "1.6.2"
|
||||
version = "1.6.4"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"auto-launch",
|
||||
@@ -5169,7 +5169,7 @@ dependencies = [
|
||||
[[package]]
|
||||
name = "sysproxy"
|
||||
version = "0.3.0"
|
||||
source = "git+https://github.com/zzzgydi/sysproxy-rs?branch=main#1402eba27022a2da7b91b3090d2f4936b6260f10"
|
||||
source = "git+https://github.com/zzzgydi/sysproxy-rs?branch=main#24e8d46cb338a6a8e28742dea6ed993cd6450780"
|
||||
dependencies = [
|
||||
"interfaces",
|
||||
"iptools",
|
||||
|
@@ -1,6 +1,6 @@
|
||||
[package]
|
||||
name = "clash-verge"
|
||||
version = "1.6.2"
|
||||
version = "1.6.4"
|
||||
description = "clash verge"
|
||||
authors = ["zzzgydi", "wonfen", "MystiPanda"]
|
||||
license = "GPL-3.0-only"
|
||||
@@ -37,7 +37,7 @@ serde = { version = "1.0", features = ["derive"] }
|
||||
reqwest = { version = "0.12", features = ["json", "rustls-tls"] }
|
||||
sysproxy = { git="https://github.com/zzzgydi/sysproxy-rs", branch = "main" }
|
||||
auto-launch = { git="https://github.com/zzzgydi/auto-launch", branch = "main" }
|
||||
tauri = { version = "1.6", features = [ "http-all", "fs-read-file", "fs-exists", "path-all", "protocol-asset", "dialog-open", "notification-all", "icon-png", "icon-ico", "clipboard-all", "global-shortcut-all", "process-all", "shell-all", "system-tray", "updater", "window-all", "devtools"] }
|
||||
tauri = { version = "1.6", features = [ "fs-read-file", "fs-exists", "path-all", "protocol-asset", "dialog-open", "notification-all", "icon-png", "icon-ico", "clipboard-all", "global-shortcut-all", "process-all", "shell-all", "system-tray", "updater", "window-all", "devtools"] }
|
||||
|
||||
[target.'cfg(windows)'.dependencies]
|
||||
runas = "=1.2.0"
|
||||
|
@@ -8,7 +8,7 @@ use crate::{ret_err, wrap_err};
|
||||
use anyhow::{Context, Result};
|
||||
use serde_yaml::Mapping;
|
||||
use std::collections::{HashMap, VecDeque};
|
||||
use sysproxy::Sysproxy;
|
||||
use sysproxy::{Autoproxy, Sysproxy};
|
||||
use tauri::{api, Manager};
|
||||
type CmdResult<T = ()> = Result<T, String>;
|
||||
|
||||
@@ -194,7 +194,6 @@ pub fn grant_permission(_core: String) -> CmdResult {
|
||||
#[tauri::command]
|
||||
pub fn get_sys_proxy() -> CmdResult<Mapping> {
|
||||
let current = wrap_err!(Sysproxy::get_system_proxy())?;
|
||||
|
||||
let mut map = Mapping::new();
|
||||
map.insert("enable".into(), current.enable.into());
|
||||
map.insert(
|
||||
@@ -206,6 +205,18 @@ pub fn get_sys_proxy() -> CmdResult<Mapping> {
|
||||
Ok(map)
|
||||
}
|
||||
|
||||
/// get the system proxy
|
||||
#[tauri::command]
|
||||
pub fn get_auto_proxy() -> CmdResult<Mapping> {
|
||||
let current = wrap_err!(Autoproxy::get_auto_proxy())?;
|
||||
|
||||
let mut map = Mapping::new();
|
||||
map.insert("enable".into(), current.enable.into());
|
||||
map.insert("url".into(), current.url.into());
|
||||
|
||||
Ok(map)
|
||||
}
|
||||
|
||||
#[tauri::command]
|
||||
pub fn get_clash_logs() -> CmdResult<VecDeque<String>> {
|
||||
Ok(logger::Logger::global().get_log())
|
||||
|
@@ -13,3 +13,8 @@ pub use self::prfitem::*;
|
||||
pub use self::profiles::*;
|
||||
pub use self::runtime::*;
|
||||
pub use self::verge::*;
|
||||
|
||||
pub const DEFAULT_PAC: &str = r#"function FindProxyForURL(url, host) {
|
||||
return "PROXY 127.0.0.1:%mixed-port%; SOCKS5 127.0.0.1:%mixed-port%; DIRECT;";
|
||||
}
|
||||
"#;
|
||||
|
@@ -1,3 +1,4 @@
|
||||
use crate::config::DEFAULT_PAC;
|
||||
use crate::utils::{dirs, help};
|
||||
use anyhow::Result;
|
||||
use log::LevelFilter;
|
||||
@@ -80,6 +81,12 @@ pub struct IVerge {
|
||||
/// proxy guard duration
|
||||
pub proxy_guard_duration: Option<u64>,
|
||||
|
||||
/// use pac mode
|
||||
pub proxy_auto_config: Option<bool>,
|
||||
|
||||
/// pac script content
|
||||
pub pac_file_content: Option<String>,
|
||||
|
||||
/// theme setting
|
||||
pub theme_setting: Option<IVergeTheme>,
|
||||
|
||||
@@ -211,6 +218,8 @@ impl IVerge {
|
||||
enable_auto_launch: Some(false),
|
||||
enable_silent_start: Some(false),
|
||||
enable_system_proxy: Some(false),
|
||||
proxy_auto_config: Some(false),
|
||||
pac_file_content: Some(DEFAULT_PAC.into()),
|
||||
enable_random_port: Some(false),
|
||||
#[cfg(not(target_os = "windows"))]
|
||||
verge_redir_port: Some(7895),
|
||||
@@ -290,6 +299,8 @@ impl IVerge {
|
||||
patch!(enable_proxy_guard);
|
||||
patch!(system_proxy_bypass);
|
||||
patch!(proxy_guard_duration);
|
||||
patch!(proxy_auto_config);
|
||||
patch!(pac_file_content);
|
||||
|
||||
patch!(theme_setting);
|
||||
patch!(web_ui_list);
|
||||
|
@@ -1,11 +1,14 @@
|
||||
use crate::{config::Config, log_err};
|
||||
use crate::{
|
||||
config::{Config, IVerge},
|
||||
log_err,
|
||||
};
|
||||
use anyhow::{anyhow, Result};
|
||||
use auto_launch::{AutoLaunch, AutoLaunchBuilder};
|
||||
use once_cell::sync::OnceCell;
|
||||
use parking_lot::Mutex;
|
||||
use std::env::current_exe;
|
||||
use std::sync::Arc;
|
||||
use sysproxy::Sysproxy;
|
||||
use sysproxy::{Autoproxy, Sysproxy};
|
||||
use tauri::async_runtime::Mutex as TokioMutex;
|
||||
|
||||
pub struct Sysopt {
|
||||
@@ -16,6 +19,13 @@ pub struct Sysopt {
|
||||
/// recover it when exit
|
||||
old_sysproxy: Arc<Mutex<Option<Sysproxy>>>,
|
||||
|
||||
/// current auto proxy setting
|
||||
cur_autoproxy: Arc<Mutex<Option<Autoproxy>>>,
|
||||
|
||||
/// record the original auto proxy
|
||||
/// recover it when exit
|
||||
old_autoproxy: Arc<Mutex<Option<Autoproxy>>>,
|
||||
|
||||
/// helps to auto launch the app
|
||||
auto_launch: Arc<Mutex<Option<AutoLaunch>>>,
|
||||
|
||||
@@ -38,6 +48,8 @@ impl Sysopt {
|
||||
SYSOPT.get_or_init(|| Sysopt {
|
||||
cur_sysproxy: Arc::new(Mutex::new(None)),
|
||||
old_sysproxy: Arc::new(Mutex::new(None)),
|
||||
cur_autoproxy: Arc::new(Mutex::new(None)),
|
||||
old_autoproxy: Arc::new(Mutex::new(None)),
|
||||
auto_launch: Arc::new(Mutex::new(None)),
|
||||
guard_state: Arc::new(TokioMutex::new(false)),
|
||||
})
|
||||
@@ -49,17 +61,18 @@ impl Sysopt {
|
||||
.latest()
|
||||
.verge_mixed_port
|
||||
.unwrap_or(Config::clash().data().get_mixed_port());
|
||||
let pac_port = IVerge::get_singleton_port();
|
||||
|
||||
let (enable, bypass) = {
|
||||
let (enable, bypass, pac) = {
|
||||
let verge = Config::verge();
|
||||
let verge = verge.latest();
|
||||
(
|
||||
verge.enable_system_proxy.unwrap_or(false),
|
||||
verge.system_proxy_bypass.clone(),
|
||||
verge.proxy_auto_config.unwrap_or(false),
|
||||
)
|
||||
};
|
||||
|
||||
let current = Sysproxy {
|
||||
let mut sys = Sysproxy {
|
||||
enable,
|
||||
host: String::from("127.0.0.1"),
|
||||
port,
|
||||
@@ -74,13 +87,32 @@ impl Sysopt {
|
||||
None => DEFAULT_BYPASS.into(),
|
||||
},
|
||||
};
|
||||
|
||||
if enable {
|
||||
let mut auto = Autoproxy {
|
||||
enable,
|
||||
url: format!("http://127.0.0.1:{pac_port}/commands/pac"),
|
||||
};
|
||||
if pac {
|
||||
sys.enable = false;
|
||||
let old = Sysproxy::get_system_proxy().ok();
|
||||
current.set_system_proxy()?;
|
||||
|
||||
sys.set_system_proxy()?;
|
||||
*self.old_sysproxy.lock() = old;
|
||||
*self.cur_sysproxy.lock() = Some(current);
|
||||
*self.cur_sysproxy.lock() = Some(sys);
|
||||
|
||||
let old = Autoproxy::get_auto_proxy().ok();
|
||||
auto.set_auto_proxy()?;
|
||||
*self.old_autoproxy.lock() = old;
|
||||
*self.cur_autoproxy.lock() = Some(auto);
|
||||
} else {
|
||||
auto.enable = false;
|
||||
let old = Autoproxy::get_auto_proxy().ok();
|
||||
auto.set_auto_proxy()?;
|
||||
*self.old_autoproxy.lock() = old;
|
||||
*self.cur_autoproxy.lock() = Some(auto);
|
||||
|
||||
let old = Sysproxy::get_system_proxy().ok();
|
||||
sys.set_system_proxy()?;
|
||||
*self.old_sysproxy.lock() = old;
|
||||
*self.cur_sysproxy.lock() = Some(sys);
|
||||
}
|
||||
|
||||
// run the system proxy guard
|
||||
@@ -92,24 +124,38 @@ impl Sysopt {
|
||||
pub fn update_sysproxy(&self) -> Result<()> {
|
||||
let mut cur_sysproxy = self.cur_sysproxy.lock();
|
||||
let old_sysproxy = self.old_sysproxy.lock();
|
||||
let mut cur_autoproxy = self.cur_autoproxy.lock();
|
||||
let old_autoproxy = self.old_autoproxy.lock();
|
||||
|
||||
if cur_sysproxy.is_none() || old_sysproxy.is_none() {
|
||||
drop(cur_sysproxy);
|
||||
drop(old_sysproxy);
|
||||
return self.init_sysproxy();
|
||||
}
|
||||
|
||||
let (enable, bypass) = {
|
||||
let (enable, bypass, pac) = {
|
||||
let verge = Config::verge();
|
||||
let verge = verge.latest();
|
||||
(
|
||||
verge.enable_system_proxy.unwrap_or(false),
|
||||
verge.system_proxy_bypass.clone(),
|
||||
verge.proxy_auto_config.unwrap_or(false),
|
||||
)
|
||||
};
|
||||
let mut sysproxy = cur_sysproxy.take().unwrap();
|
||||
if pac {
|
||||
if cur_autoproxy.is_none() || old_autoproxy.is_none() {
|
||||
drop(cur_autoproxy);
|
||||
drop(old_autoproxy);
|
||||
return self.init_sysproxy();
|
||||
}
|
||||
} else {
|
||||
if cur_sysproxy.is_none() || old_sysproxy.is_none() {
|
||||
drop(cur_sysproxy);
|
||||
drop(old_sysproxy);
|
||||
return self.init_sysproxy();
|
||||
}
|
||||
}
|
||||
let port = Config::verge()
|
||||
.latest()
|
||||
.verge_mixed_port
|
||||
.unwrap_or(Config::clash().data().get_mixed_port());
|
||||
let pac_port = IVerge::get_singleton_port();
|
||||
|
||||
sysproxy.enable = enable;
|
||||
let mut sysproxy = cur_sysproxy.take().unwrap();
|
||||
sysproxy.bypass = match bypass {
|
||||
Some(bypass) => {
|
||||
if bypass.is_empty() {
|
||||
@@ -120,15 +166,26 @@ impl Sysopt {
|
||||
}
|
||||
None => DEFAULT_BYPASS.into(),
|
||||
};
|
||||
|
||||
let port = Config::verge()
|
||||
.latest()
|
||||
.verge_mixed_port
|
||||
.unwrap_or(Config::clash().data().get_mixed_port());
|
||||
sysproxy.port = port;
|
||||
|
||||
sysproxy.set_system_proxy()?;
|
||||
*cur_sysproxy = Some(sysproxy);
|
||||
let mut autoproxy = cur_autoproxy.take().unwrap();
|
||||
autoproxy.url = format!("http://127.0.0.1:{pac_port}/commands/pac");
|
||||
|
||||
if pac {
|
||||
sysproxy.enable = false;
|
||||
sysproxy.set_system_proxy()?;
|
||||
*cur_sysproxy = Some(sysproxy);
|
||||
autoproxy.enable = enable;
|
||||
autoproxy.set_auto_proxy()?;
|
||||
*cur_autoproxy = Some(autoproxy);
|
||||
} else {
|
||||
autoproxy.enable = false;
|
||||
autoproxy.set_auto_proxy()?;
|
||||
*cur_autoproxy = Some(autoproxy);
|
||||
sysproxy.enable = enable;
|
||||
sysproxy.set_system_proxy()?;
|
||||
*cur_sysproxy = Some(sysproxy);
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
@@ -137,8 +194,11 @@ impl Sysopt {
|
||||
pub fn reset_sysproxy(&self) -> Result<()> {
|
||||
let mut cur_sysproxy = self.cur_sysproxy.lock();
|
||||
let mut old_sysproxy = self.old_sysproxy.lock();
|
||||
let mut cur_autoproxy = self.cur_autoproxy.lock();
|
||||
let mut old_autoproxy = self.old_autoproxy.lock();
|
||||
|
||||
let cur_sysproxy = cur_sysproxy.take();
|
||||
let cur_autoproxy = cur_autoproxy.take();
|
||||
|
||||
if let Some(mut old) = old_sysproxy.take() {
|
||||
// 如果原代理和当前代理 端口一致,就disable关闭,否则就恢复原代理设置
|
||||
@@ -162,6 +222,28 @@ impl Sysopt {
|
||||
log::info!(target: "app", "reset proxy with no action");
|
||||
}
|
||||
|
||||
if let Some(mut old) = old_autoproxy.take() {
|
||||
// 如果原代理和当前代理 URL一致,就disable关闭,否则就恢复原代理设置
|
||||
// 当前没有设置代理的时候,不确定旧设置是否和当前一致,全关了
|
||||
let url_same = cur_autoproxy.map_or(true, |cur| old.url == cur.url);
|
||||
|
||||
if old.enable && url_same {
|
||||
old.enable = false;
|
||||
log::info!(target: "app", "reset proxy by disabling the original proxy");
|
||||
} else {
|
||||
log::info!(target: "app", "reset proxy to the original proxy");
|
||||
}
|
||||
|
||||
old.set_auto_proxy()?;
|
||||
} else if let Some(mut cur @ Autoproxy { enable: true, .. }) = cur_autoproxy {
|
||||
// 没有原代理,就按现在的代理设置disable即可
|
||||
log::info!(target: "app", "reset proxy by disabling the current proxy");
|
||||
cur.enable = false;
|
||||
cur.set_auto_proxy()?;
|
||||
} else {
|
||||
log::info!(target: "app", "reset proxy with no action");
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
@@ -267,7 +349,7 @@ impl Sysopt {
|
||||
loop {
|
||||
sleep(Duration::from_secs(wait_secs)).await;
|
||||
|
||||
let (enable, guard, guard_duration, bypass) = {
|
||||
let (enable, guard, guard_duration, bypass, pac) = {
|
||||
let verge = Config::verge();
|
||||
let verge = verge.latest();
|
||||
(
|
||||
@@ -275,6 +357,7 @@ impl Sysopt {
|
||||
verge.enable_proxy_guard.unwrap_or(false),
|
||||
verge.proxy_guard_duration.unwrap_or(10),
|
||||
verge.system_proxy_bypass.clone(),
|
||||
verge.proxy_auto_config.unwrap_or(false),
|
||||
)
|
||||
};
|
||||
|
||||
@@ -294,24 +377,32 @@ impl Sysopt {
|
||||
.verge_mixed_port
|
||||
.unwrap_or(Config::clash().data().get_mixed_port())
|
||||
};
|
||||
|
||||
let sysproxy = Sysproxy {
|
||||
enable: true,
|
||||
host: "127.0.0.1".into(),
|
||||
port,
|
||||
bypass: match bypass {
|
||||
Some(bypass) => {
|
||||
if bypass.is_empty() {
|
||||
DEFAULT_BYPASS.into()
|
||||
} else {
|
||||
bypass
|
||||
let pac_port = IVerge::get_singleton_port();
|
||||
if pac {
|
||||
let autoproxy = Autoproxy {
|
||||
enable: true,
|
||||
url: format!("http://127.0.0.1:{pac_port}/commands/pac"),
|
||||
};
|
||||
log_err!(autoproxy.set_auto_proxy());
|
||||
} else {
|
||||
let sysproxy = Sysproxy {
|
||||
enable: true,
|
||||
host: "127.0.0.1".into(),
|
||||
port,
|
||||
bypass: match bypass {
|
||||
Some(bypass) => {
|
||||
if bypass.is_empty() {
|
||||
DEFAULT_BYPASS.into()
|
||||
} else {
|
||||
bypass
|
||||
}
|
||||
}
|
||||
}
|
||||
None => DEFAULT_BYPASS.into(),
|
||||
},
|
||||
};
|
||||
None => DEFAULT_BYPASS.into(),
|
||||
},
|
||||
};
|
||||
|
||||
log_err!(sysproxy.set_system_proxy());
|
||||
log_err!(sysproxy.set_system_proxy());
|
||||
}
|
||||
}
|
||||
|
||||
let mut state = guard_state.lock().await;
|
||||
|
@@ -177,6 +177,8 @@ pub async fn patch_verge(patch: IVerge) -> Result<()> {
|
||||
let tun_mode = patch.enable_tun_mode;
|
||||
let auto_launch = patch.enable_auto_launch;
|
||||
let system_proxy = patch.enable_system_proxy;
|
||||
let pac = patch.proxy_auto_config;
|
||||
let pac_content = patch.pac_file_content;
|
||||
let proxy_bypass = patch.system_proxy_bypass;
|
||||
let language = patch.language;
|
||||
let port = patch.verge_mixed_port;
|
||||
@@ -219,7 +221,12 @@ pub async fn patch_verge(patch: IVerge) -> Result<()> {
|
||||
if auto_launch.is_some() {
|
||||
sysopt::Sysopt::global().update_launch()?;
|
||||
}
|
||||
if system_proxy.is_some() || proxy_bypass.is_some() || port.is_some() {
|
||||
if system_proxy.is_some()
|
||||
|| proxy_bypass.is_some()
|
||||
|| port.is_some()
|
||||
|| pac.is_some()
|
||||
|| pac_content.is_some()
|
||||
{
|
||||
sysopt::Sysopt::global().update_sysproxy()?;
|
||||
sysopt::Sysopt::global().guard_proxy();
|
||||
}
|
||||
|
@@ -36,6 +36,7 @@ fn main() -> std::io::Result<()> {
|
||||
.invoke_handler(tauri::generate_handler![
|
||||
// common
|
||||
cmds::get_sys_proxy,
|
||||
cmds::get_auto_proxy,
|
||||
cmds::open_app_dir,
|
||||
cmds::open_logs_dir,
|
||||
cmds::open_web_url,
|
||||
|
@@ -1,7 +1,7 @@
|
||||
extern crate warp;
|
||||
|
||||
use super::resolve;
|
||||
use crate::config::IVerge;
|
||||
use crate::config::{Config, IVerge, DEFAULT_PAC};
|
||||
use anyhow::{bail, Result};
|
||||
use port_scanner::local_port_available;
|
||||
use std::convert::Infallible;
|
||||
@@ -64,6 +64,22 @@ pub fn embed_server(app_handle: AppHandle) {
|
||||
"ok"
|
||||
});
|
||||
|
||||
let pac = warp::path!("commands" / "pac").map(move || {
|
||||
let content = Config::verge()
|
||||
.latest()
|
||||
.pac_file_content
|
||||
.clone()
|
||||
.unwrap_or(DEFAULT_PAC.to_string());
|
||||
let port = Config::verge()
|
||||
.latest()
|
||||
.verge_mixed_port
|
||||
.unwrap_or(Config::clash().data().get_mixed_port());
|
||||
let content = content.replace("%mixed-port%", &format!("{}", port));
|
||||
warp::http::Response::builder()
|
||||
.header("Content-Type", "application/x-ns-proxy-autoconfig")
|
||||
.body(content)
|
||||
.unwrap_or_default()
|
||||
});
|
||||
let scheme = warp::path!("commands" / "scheme")
|
||||
.and(warp::query::<QueryParam>())
|
||||
.and_then(scheme_handler);
|
||||
@@ -72,7 +88,7 @@ pub fn embed_server(app_handle: AppHandle) {
|
||||
resolve::resolve_scheme(query.param).await;
|
||||
Ok("ok")
|
||||
}
|
||||
let commands = ping.or(visible).or(scheme);
|
||||
let commands = ping.or(visible).or(pac).or(scheme);
|
||||
warp::serve(commands).run(([127, 0, 0, 1], port)).await;
|
||||
});
|
||||
}
|
||||
|
@@ -2,7 +2,7 @@
|
||||
"$schema": "../node_modules/@tauri-apps/cli/schema.json",
|
||||
"package": {
|
||||
"productName": "Clash Verge",
|
||||
"version": "1.6.2"
|
||||
"version": "1.6.4"
|
||||
},
|
||||
"build": {
|
||||
"distDir": "../dist",
|
||||
@@ -38,10 +38,6 @@
|
||||
"pubkey": "dW50cnVzdGVkIGNvbW1lbnQ6IG1pbmlzaWduIHB1YmxpYyBrZXk6IEQyOEMyRjBCQkVGOUJEREYKUldUZnZmbStDeStNMHU5Mmo1N24xQXZwSVRYbXA2NUpzZE5oVzlqeS9Bc0t6RVV4MmtwVjBZaHgK"
|
||||
},
|
||||
"allowlist": {
|
||||
"http": {
|
||||
"all": true,
|
||||
"scope": ["http://**", "http://**"]
|
||||
},
|
||||
"shell": {
|
||||
"all": true
|
||||
},
|
||||
|
@@ -36,6 +36,7 @@ export const LayoutControl = () => {
|
||||
<ButtonGroup
|
||||
variant="text"
|
||||
sx={{
|
||||
zIndex: 1000,
|
||||
height: "100%",
|
||||
".MuiButtonGroup-grouped": {
|
||||
borderRadius: "0px",
|
||||
|
@@ -57,6 +57,23 @@ configureMonacoYaml(monaco, {
|
||||
});
|
||||
// PAC definition
|
||||
monaco.languages.typescript.javascriptDefaults.addExtraLib(pac, "pac.d.ts");
|
||||
monaco.languages.registerCompletionItemProvider("javascript", {
|
||||
provideCompletionItems: (model, position) => ({
|
||||
suggestions: [
|
||||
{
|
||||
label: "%mixed-port%",
|
||||
kind: monaco.languages.CompletionItemKind.Text,
|
||||
insertText: "%mixed-port%",
|
||||
range: {
|
||||
startLineNumber: position.lineNumber,
|
||||
endLineNumber: position.lineNumber,
|
||||
startColumn: model.getWordUntilPosition(position).startColumn - 1,
|
||||
endColumn: model.getWordUntilPosition(position).endColumn - 1,
|
||||
},
|
||||
},
|
||||
],
|
||||
}),
|
||||
});
|
||||
|
||||
export const EditorViewer = (props: Props) => {
|
||||
const {
|
||||
@@ -114,7 +131,7 @@ export const EditorViewer = (props: Props) => {
|
||||
padding: {
|
||||
top: 33, // 顶部padding防止遮挡snippets
|
||||
},
|
||||
fontFamily: `Fira Code, Roboto Mono, Roboto, Source Code Pro, Menlo, Monaco, Consolas, Courier New, monospace, "Apple Color Emoji"${
|
||||
fontFamily: `Fira Code, JetBrains Mono, Roboto Mono, "Source Code Pro", Consolas, Menlo, Monaco, monospace, "Courier New", "Apple Color Emoji"${
|
||||
getSystem() === "windows" ? ", twemoji mozilla" : ""
|
||||
}`,
|
||||
fontLigatures: true, // 连字符
|
||||
|
@@ -10,23 +10,34 @@ import {
|
||||
styled,
|
||||
TextField,
|
||||
Typography,
|
||||
Button,
|
||||
} from "@mui/material";
|
||||
import { useVerge } from "@/hooks/use-verge";
|
||||
import { getSystemProxy } from "@/services/cmds";
|
||||
import { getSystemProxy, getAutotemProxy } from "@/services/cmds";
|
||||
import { BaseDialog, DialogRef, Notice, Switch } from "@/components/base";
|
||||
import { Edit } from "@mui/icons-material";
|
||||
import { EditorViewer } from "@/components/profile/editor-viewer";
|
||||
const DEFAULT_PAC = `function FindProxyForURL(url, host) {
|
||||
return "PROXY 127.0.0.1:%mixed-port%; SOCKS5 127.0.0.1:%mixed-port%; DIRECT;";
|
||||
}`;
|
||||
|
||||
export const SysproxyViewer = forwardRef<DialogRef>((props, ref) => {
|
||||
const { t } = useTranslation();
|
||||
|
||||
const [open, setOpen] = useState(false);
|
||||
|
||||
const [editorOpen, setEditorOpen] = useState(false);
|
||||
const { verge, patchVerge } = useVerge();
|
||||
|
||||
type SysProxy = Awaited<ReturnType<typeof getSystemProxy>>;
|
||||
const [sysproxy, setSysproxy] = useState<SysProxy>();
|
||||
|
||||
type AutoProxy = Awaited<ReturnType<typeof getAutotemProxy>>;
|
||||
const [autoproxy, setAutoproxy] = useState<AutoProxy>();
|
||||
|
||||
const {
|
||||
enable_system_proxy: enabled,
|
||||
proxy_auto_config,
|
||||
pac_file_content,
|
||||
enable_proxy_guard,
|
||||
system_proxy_bypass,
|
||||
proxy_guard_duration,
|
||||
@@ -36,6 +47,8 @@ export const SysproxyViewer = forwardRef<DialogRef>((props, ref) => {
|
||||
guard: enable_proxy_guard,
|
||||
bypass: system_proxy_bypass,
|
||||
duration: proxy_guard_duration ?? 10,
|
||||
pac: proxy_auto_config,
|
||||
pac_content: pac_file_content ?? DEFAULT_PAC,
|
||||
});
|
||||
|
||||
useImperativeHandle(ref, () => ({
|
||||
@@ -45,8 +58,11 @@ export const SysproxyViewer = forwardRef<DialogRef>((props, ref) => {
|
||||
guard: enable_proxy_guard,
|
||||
bypass: system_proxy_bypass,
|
||||
duration: proxy_guard_duration ?? 10,
|
||||
pac: proxy_auto_config,
|
||||
pac_content: pac_file_content ?? DEFAULT_PAC,
|
||||
});
|
||||
getSystemProxy().then((p) => setSysproxy(p));
|
||||
getAutotemProxy().then((p) => setAutoproxy(p));
|
||||
},
|
||||
close: () => setOpen(false),
|
||||
}));
|
||||
@@ -68,6 +84,12 @@ export const SysproxyViewer = forwardRef<DialogRef>((props, ref) => {
|
||||
if (value.bypass !== system_proxy_bypass) {
|
||||
patch.system_proxy_bypass = value.bypass;
|
||||
}
|
||||
if (value.pac !== proxy_auto_config) {
|
||||
patch.proxy_auto_config = value.pac;
|
||||
}
|
||||
if (value.pac_content !== pac_file_content) {
|
||||
patch.pac_file_content = value.pac_content;
|
||||
}
|
||||
|
||||
try {
|
||||
await patchVerge(patch);
|
||||
@@ -89,6 +111,15 @@ export const SysproxyViewer = forwardRef<DialogRef>((props, ref) => {
|
||||
onOk={onSave}
|
||||
>
|
||||
<List>
|
||||
<ListItem sx={{ padding: "5px 2px" }}>
|
||||
<ListItemText primary={t("Use PAC Mode")} />
|
||||
<Switch
|
||||
edge="end"
|
||||
disabled={!enabled}
|
||||
checked={value.pac}
|
||||
onChange={(_, e) => setValue((v) => ({ ...v, pac: e }))}
|
||||
/>
|
||||
</ListItem>
|
||||
<ListItem sx={{ padding: "5px 2px" }}>
|
||||
<ListItemText primary={t("Proxy Guard")} />
|
||||
<Switch
|
||||
@@ -117,25 +148,67 @@ export const SysproxyViewer = forwardRef<DialogRef>((props, ref) => {
|
||||
}}
|
||||
/>
|
||||
</ListItem>
|
||||
|
||||
<ListItem sx={{ padding: "5px 2px", alignItems: "start" }}>
|
||||
<ListItemText primary={t("Proxy Bypass")} sx={{ padding: "3px 0" }} />
|
||||
</ListItem>
|
||||
<ListItem sx={{ padding: "5px 2px" }}>
|
||||
<TextField
|
||||
disabled={!enabled}
|
||||
size="small"
|
||||
autoComplete="off"
|
||||
multiline
|
||||
rows={4}
|
||||
sx={{ width: "100%" }}
|
||||
value={value.bypass}
|
||||
placeholder={sysproxy?.bypass || `-`}
|
||||
onChange={(e) =>
|
||||
setValue((v) => ({ ...v, bypass: e.target.value }))
|
||||
}
|
||||
/>
|
||||
</ListItem>
|
||||
{!value.pac && (
|
||||
<>
|
||||
<ListItem sx={{ padding: "5px 2px", alignItems: "start" }}>
|
||||
<ListItemText
|
||||
primary={t("Proxy Bypass")}
|
||||
sx={{ padding: "3px 0" }}
|
||||
/>
|
||||
</ListItem>
|
||||
<ListItem sx={{ padding: "5px 2px" }}>
|
||||
<TextField
|
||||
disabled={!enabled}
|
||||
size="small"
|
||||
autoComplete="off"
|
||||
multiline
|
||||
rows={4}
|
||||
sx={{ width: "100%" }}
|
||||
value={value.bypass}
|
||||
placeholder={sysproxy?.bypass || `-`}
|
||||
onChange={(e) =>
|
||||
setValue((v) => ({ ...v, bypass: e.target.value }))
|
||||
}
|
||||
/>
|
||||
</ListItem>
|
||||
</>
|
||||
)}
|
||||
{value.pac && (
|
||||
<>
|
||||
<ListItem sx={{ padding: "5px 2px", alignItems: "start" }}>
|
||||
<ListItemText
|
||||
primary={t("PAC Script Content")}
|
||||
sx={{ padding: "3px 0" }}
|
||||
/>
|
||||
<Button
|
||||
startIcon={<Edit />}
|
||||
variant="outlined"
|
||||
onClick={() => {
|
||||
setEditorOpen(true);
|
||||
}}
|
||||
>
|
||||
{t("Edit")} PAC
|
||||
</Button>
|
||||
<EditorViewer
|
||||
title={`${t("Edit")} PAC`}
|
||||
mode="text"
|
||||
property={value.pac_content ?? ""}
|
||||
open={editorOpen}
|
||||
language="javascript"
|
||||
onChange={(content) => {
|
||||
let pac = DEFAULT_PAC;
|
||||
if (content && content.trim().length > 0) {
|
||||
pac = content;
|
||||
}
|
||||
setValue((v) => ({ ...v, pac_content: pac }));
|
||||
}}
|
||||
onClose={() => {
|
||||
setEditorOpen(false);
|
||||
}}
|
||||
/>
|
||||
</ListItem>
|
||||
</>
|
||||
)}
|
||||
</List>
|
||||
|
||||
<Box sx={{ mt: 2.5 }}>
|
||||
@@ -146,29 +219,42 @@ export const SysproxyViewer = forwardRef<DialogRef>((props, ref) => {
|
||||
<FlexBox>
|
||||
<Typography className="label">{t("Enable status")}</Typography>
|
||||
<Typography className="value">
|
||||
{(!!sysproxy?.enable).toString()}
|
||||
{value.pac
|
||||
? (!!autoproxy?.enable).toString()
|
||||
: (!!sysproxy?.enable).toString()}
|
||||
</Typography>
|
||||
</FlexBox>
|
||||
{!value.pac && (
|
||||
<>
|
||||
<FlexBox>
|
||||
<Typography className="label">{t("Server Addr")}</Typography>
|
||||
<Typography className="value">
|
||||
{sysproxy?.server || "-"}
|
||||
</Typography>
|
||||
</FlexBox>
|
||||
|
||||
<FlexBox>
|
||||
<Typography className="label">{t("Server Addr")}</Typography>
|
||||
<Typography className="value">{sysproxy?.server || "-"}</Typography>
|
||||
</FlexBox>
|
||||
|
||||
<FlexBox>
|
||||
<Typography className="label">{t("Bypass")}</Typography>
|
||||
</FlexBox>
|
||||
<FlexBox>
|
||||
<TextField
|
||||
disabled={true}
|
||||
size="small"
|
||||
autoComplete="off"
|
||||
multiline
|
||||
rows={4}
|
||||
sx={{ width: "100%" }}
|
||||
value={sysproxy?.bypass || "-"}
|
||||
/>
|
||||
</FlexBox>
|
||||
<FlexBox>
|
||||
<Typography className="label">{t("Bypass")}</Typography>
|
||||
</FlexBox>
|
||||
<FlexBox>
|
||||
<TextField
|
||||
disabled={true}
|
||||
size="small"
|
||||
autoComplete="off"
|
||||
multiline
|
||||
rows={4}
|
||||
sx={{ width: "100%" }}
|
||||
value={sysproxy?.bypass || "-"}
|
||||
/>
|
||||
</FlexBox>
|
||||
</>
|
||||
)}
|
||||
{value.pac && (
|
||||
<FlexBox>
|
||||
<Typography className="label">{t("PAC URL")}</Typography>
|
||||
<Typography className="value">{autoproxy?.url || "-"}</Typography>
|
||||
</FlexBox>
|
||||
)}
|
||||
</Box>
|
||||
</BaseDialog>
|
||||
);
|
||||
|
@@ -118,6 +118,9 @@
|
||||
"System Proxy Setting": "System Proxy Setting",
|
||||
"Open UWP tool": "Open UWP tool",
|
||||
"Update GeoData": "Update GeoData",
|
||||
"Use PAC Mode": "Use PAC Mode",
|
||||
"PAC URL": "PAC URL",
|
||||
"PAC Script Content": "PAC Script Content",
|
||||
"Proxy Guard": "Proxy Guard",
|
||||
"Guard Duration": "Guard Duration",
|
||||
"Proxy Bypass": "Proxy Bypass",
|
||||
|
@@ -118,6 +118,9 @@
|
||||
"System Proxy Setting": "تنظیمات پراکسی سیستم",
|
||||
"Open UWP tool": "باز کردن ابزار UWP",
|
||||
"Update GeoData": "بهروزرسانی GeoData",
|
||||
"Use PAC Mode": "استفاده از حالت PAC",
|
||||
"PAC URL": "PAC URL",
|
||||
"PAC Script Content": "محتوای اسکریپت PAC",
|
||||
"Proxy Guard": "محافظ پراکسی",
|
||||
"Guard Duration": "مدت محافظت",
|
||||
"Proxy Bypass": "دور زدن پراکسی",
|
||||
|
@@ -118,6 +118,9 @@
|
||||
"System Proxy Setting": "Настройка системного прокси",
|
||||
"Open UWP tool": "Открыть UWP инструмент",
|
||||
"Update GeoData": "Обновление GeoData",
|
||||
"Use PAC Mode": "Используйте режим PAC.",
|
||||
"PAC URL": "Адрес PAC",
|
||||
"PAC Script Content": "Содержание сценария PAC",
|
||||
"Proxy Guard": "Защита прокси",
|
||||
"Guard Duration": "Период защиты",
|
||||
"Proxy Bypass": "Игнорирование прокси",
|
||||
|
@@ -118,6 +118,9 @@
|
||||
"System Proxy Setting": "系统代理设置",
|
||||
"Open UWP tool": "UWP 工具",
|
||||
"Update GeoData": "更新 GeoData",
|
||||
"Use PAC Mode": "使用PAC模式",
|
||||
"PAC URL": "PAC 地址",
|
||||
"PAC Script Content": "PAC 脚本内容",
|
||||
"Proxy Guard": "系统代理守卫",
|
||||
"Guard Duration": "代理守卫间隔",
|
||||
"Proxy Bypass": "代理绕过",
|
||||
|
@@ -1,4 +1,3 @@
|
||||
import axiosTauriApiAdapter from "axios-tauri-api-adapter";
|
||||
import axios, { AxiosInstance } from "axios";
|
||||
import { getClashInfo } from "./cmds";
|
||||
|
||||
@@ -26,7 +25,6 @@ export const getAxios = async (force: boolean = false) => {
|
||||
} catch {}
|
||||
|
||||
axiosIns = axios.create({
|
||||
adapter: axiosTauriApiAdapter,
|
||||
baseURL: `http://${server}`,
|
||||
headers: secret ? { Authorization: `Bearer ${secret}` } : {},
|
||||
timeout: 15000,
|
||||
|
@@ -127,6 +127,13 @@ export async function getSystemProxy() {
|
||||
}>("get_sys_proxy");
|
||||
}
|
||||
|
||||
export async function getAutotemProxy() {
|
||||
return invoke<{
|
||||
enable: boolean;
|
||||
url: string;
|
||||
}>("get_auto_proxy");
|
||||
}
|
||||
|
||||
export async function changeClashCore(clashCore: string) {
|
||||
return invoke<any>("change_clash_core", { clashCore });
|
||||
}
|
||||
|
2
clash-verge-rev/src/services/types.d.ts
vendored
2
clash-verge-rev/src/services/types.d.ts
vendored
@@ -216,6 +216,8 @@ interface IVergeConfig {
|
||||
enable_service_mode?: boolean;
|
||||
enable_silent_start?: boolean;
|
||||
enable_system_proxy?: boolean;
|
||||
proxy_auto_config?: boolean;
|
||||
pac_file_content?: string;
|
||||
enable_random_port?: boolean;
|
||||
verge_mixed_port?: number;
|
||||
verge_socks_port?: number;
|
||||
|
@@ -61,7 +61,8 @@ func (b *baseTransporter) RelayTCPConn(c net.Conn, handshakeF TCPHandShakeF) err
|
||||
ctx, c, buffer, constant.SniffTimeOut,
|
||||
sniff.TLSClientHello, sniff.HTTPHost)
|
||||
if err != nil {
|
||||
b.l.Warnf("sniff error: %s", err)
|
||||
// this mean no protocol sniffed
|
||||
b.l.Debug("sniff error: %s", err)
|
||||
}
|
||||
if sniffMetadata != nil {
|
||||
b.l.Infof("sniffed protocol: %s", sniffMetadata.Protocol)
|
||||
|
@@ -1,2 +1,2 @@
|
||||
LINUX_VERSION-5.10 = .217
|
||||
LINUX_KERNEL_HASH-5.10.217 = c52bc1ffc396c11bce335c9ee5cd55fe4213cbc1fb4026ff62bb90c864c61f62
|
||||
LINUX_VERSION-5.10 = .218
|
||||
LINUX_KERNEL_HASH-5.10.218 = 9c36b243e8c3ec1d5963366618f336710b84340bf95be2037b26c452392cb2d6
|
||||
|
@@ -1,2 +1,2 @@
|
||||
LINUX_VERSION-5.15 = .159
|
||||
LINUX_KERNEL_HASH-5.15.159 = 3478fe50225e9c88e09cf114f38e3fb71e82d9fdcc356aa1257d721199b341c5
|
||||
LINUX_VERSION-5.15 = .160
|
||||
LINUX_KERNEL_HASH-5.15.160 = f41e718e33b88f269a6b6a7653e5e9824c4ba541f6ffe5bf26ecc37c540a1b05
|
||||
|
@@ -1,2 +1,2 @@
|
||||
LINUX_VERSION-5.4 = .276
|
||||
LINUX_KERNEL_HASH-5.4.276 = e2712ebd4421ffa5b25a366659ecfbe1b45a444027ee2fe57369676453e86e07
|
||||
LINUX_VERSION-5.4 = .277
|
||||
LINUX_KERNEL_HASH-5.4.277 = 7e1f5b28588e49ddfd18e7772476e4e8b52bdc9c3e19beafcbb7c103e6c01f51
|
||||
|
@@ -1,2 +1,2 @@
|
||||
LINUX_VERSION-6.1 = .91
|
||||
LINUX_KERNEL_HASH-6.1.91 = 880ace63ca2291b8b639e9bd862cc828649d3e1e00ccfee5861473debd2e4dec
|
||||
LINUX_VERSION-6.1 = .92
|
||||
LINUX_KERNEL_HASH-6.1.92 = 9019f427bfdc9ced5bc954d760d37ac08c0cdffb45ad28087fc45a73e64336c9
|
||||
|
@@ -1,2 +1,2 @@
|
||||
LINUX_VERSION-6.6 = .31
|
||||
LINUX_KERNEL_HASH-6.6.31 = d6ecff966f8c95ec4cb3bb303904f757b7de6a6bcfef0d0771cb852158e61c20
|
||||
LINUX_VERSION-6.6 = .32
|
||||
LINUX_KERNEL_HASH-6.6.32 = aaa824eaf07f61911d22b75ff090a403c3dd0bd73e23933e0bba8b5971436ce1
|
||||
|
@@ -23,6 +23,7 @@ PKG_LICENSE:=GPL-2.0
|
||||
PKG_CONFIG_DEPENDS += \
|
||||
CONFIG_SIGNED_PACKAGES CONFIG_TARGET_INIT_PATH CONFIG_TARGET_PREINIT_DISABLE_FAILSAFE \
|
||||
CONFIG_NAND_SUPPORT \
|
||||
CONFIG_LEGACY_SDCARD_SUPPORT \
|
||||
CONFIG_EMMC_SUPPORT \
|
||||
CONFIG_CLEAN_IPKG \
|
||||
CONFIG_PER_FEED_REPO \
|
||||
@@ -125,6 +126,12 @@ ifeq ($(CONFIG_NAND_SUPPORT),)
|
||||
endef
|
||||
endif
|
||||
|
||||
ifeq ($(CONFIG_LEGACY_SDCARD_SUPPORT),)
|
||||
define Package/base-files/legacy-sdcard-support
|
||||
rm -f $(1)/lib/upgrade/legacy-sdcard.sh
|
||||
endef
|
||||
endif
|
||||
|
||||
ifeq ($(CONFIG_EMMC_SUPPORT),)
|
||||
define Package/base-files/emmc-support
|
||||
rm -f $(1)/lib/upgrade/emmc.sh
|
||||
@@ -135,6 +142,7 @@ define Package/base-files/install
|
||||
$(CP) ./files/* $(1)/
|
||||
$(Package/base-files/install-key)
|
||||
$(Package/base-files/nand-support)
|
||||
$(Package/base-files/legacy-sdcard-support)
|
||||
$(Package/base-files/emmc-support)
|
||||
if [ -d $(GENERIC_PLATFORM_DIR)/base-files/. ]; then \
|
||||
$(CP) $(GENERIC_PLATFORM_DIR)/base-files/* $(1)/; \
|
||||
|
91
lede/package/base-files/files/lib/upgrade/legacy-sdcard.sh
Normal file
91
lede/package/base-files/files/lib/upgrade/legacy-sdcard.sh
Normal file
@@ -0,0 +1,91 @@
|
||||
legacy_sdcard_check_image() {
|
||||
local file="$1"
|
||||
local diskdev partdev diff
|
||||
|
||||
export_bootdevice && export_partdevice diskdev 0 || {
|
||||
v "Unable to determine upgrade device"
|
||||
return 1
|
||||
}
|
||||
|
||||
get_partitions "/dev/$diskdev" bootdisk
|
||||
|
||||
v "Extract boot sector from the image"
|
||||
get_image_dd "$1" of=/tmp/image.bs count=1 bs=512b
|
||||
|
||||
get_partitions /tmp/image.bs image
|
||||
|
||||
#compare tables
|
||||
diff="$(grep -F -x -v -f /tmp/partmap.bootdisk /tmp/partmap.image)"
|
||||
|
||||
rm -f /tmp/image.bs /tmp/partmap.bootdisk /tmp/partmap.image
|
||||
|
||||
if [ -n "$diff" ]; then
|
||||
v "Partition layout has changed. Full image will be written."
|
||||
ask_bool 0 "Abort" && exit 1
|
||||
return 0
|
||||
fi
|
||||
}
|
||||
|
||||
legacy_sdcard_do_upgrade() {
|
||||
local board=$(board_name)
|
||||
local diskdev partdev diff
|
||||
|
||||
export_bootdevice && export_partdevice diskdev 0 || {
|
||||
v "Unable to determine upgrade device"
|
||||
return 1
|
||||
}
|
||||
|
||||
sync
|
||||
|
||||
if [ "$UPGRADE_OPT_SAVE_PARTITIONS" = "1" ]; then
|
||||
get_partitions "/dev/$diskdev" bootdisk
|
||||
|
||||
v "Extract boot sector from the image"
|
||||
get_image_dd "$1" of=/tmp/image.bs count=1 bs=512b
|
||||
|
||||
get_partitions /tmp/image.bs image
|
||||
|
||||
#compare tables
|
||||
diff="$(grep -F -x -v -f /tmp/partmap.bootdisk /tmp/partmap.image)"
|
||||
else
|
||||
diff=1
|
||||
fi
|
||||
|
||||
if [ -n "$diff" ]; then
|
||||
get_image_dd "$1" of="/dev/$diskdev" bs=4096 conv=fsync
|
||||
|
||||
# Separate removal and addtion is necessary; otherwise, partition 1
|
||||
# will be missing if it overlaps with the old partition 2
|
||||
partx -d - "/dev/$diskdev"
|
||||
partx -a - "/dev/$diskdev"
|
||||
else
|
||||
v "Writing bootloader to /dev/$diskdev"
|
||||
get_image_dd "$1" of="$diskdev" bs=512 skip=1 seek=1 count=2048 conv=fsync
|
||||
#iterate over each partition from the image and write it to the boot disk
|
||||
while read part start size; do
|
||||
if export_partdevice partdev $part; then
|
||||
v "Writing image to /dev/$partdev..."
|
||||
get_image_dd "$1" of="/dev/$partdev" ibs="512" obs=1M skip="$start" count="$size" conv=fsync
|
||||
else
|
||||
v "Unable to find partition $part device, skipped."
|
||||
fi
|
||||
done < /tmp/partmap.image
|
||||
|
||||
v "Writing new UUID to /dev/$diskdev..."
|
||||
get_image_dd "$1" of="/dev/$diskdev" bs=1 skip=440 count=4 seek=440 conv=fsync
|
||||
fi
|
||||
|
||||
sleep 1
|
||||
}
|
||||
|
||||
legacy_sdcard_copy_config() {
|
||||
local partdev
|
||||
|
||||
if export_partdevice partdev 1; then
|
||||
mkdir -p /boot
|
||||
[ -f /boot/kernel.img ] || mount -o rw,noatime /dev/$partdev /boot
|
||||
cp -af "$UPGRADE_BACKUP" "/boot/$BACKUP_FILE"
|
||||
sync
|
||||
umount /boot
|
||||
fi
|
||||
}
|
@@ -0,0 +1,10 @@
|
||||
--- a/wpa_supplicant/Makefile
|
||||
+++ b/wpa_supplicant/Makefile
|
||||
@@ -339,6 +339,7 @@
|
||||
|
||||
ifdef CONFIG_MBO
|
||||
CONFIG_WNM=y
|
||||
+NEED_GAS=y
|
||||
endif
|
||||
|
||||
ifdef CONFIG_WNM
|
@@ -1833,7 +1833,7 @@ Signed-off-by: David S. Miller <davem@davemloft.net>
|
||||
}
|
||||
--- a/drivers/net/ethernet/broadcom/genet/bcmgenet.c
|
||||
+++ b/drivers/net/ethernet/broadcom/genet/bcmgenet.c
|
||||
@@ -3467,10 +3467,11 @@ static int bcmgenet_probe(struct platfor
|
||||
@@ -3478,10 +3478,11 @@ static int bcmgenet_probe(struct platfor
|
||||
const struct of_device_id *of_id = NULL;
|
||||
struct bcmgenet_priv *priv;
|
||||
struct net_device *dev;
|
||||
@@ -1846,7 +1846,7 @@ Signed-off-by: David S. Miller <davem@davemloft.net>
|
||||
|
||||
/* Up to GENET_MAX_MQ_CNT + 1 TX queues and RX queues */
|
||||
dev = alloc_etherdev_mqs(sizeof(*priv), GENET_MAX_MQ_CNT + 1,
|
||||
@@ -3497,14 +3498,15 @@ static int bcmgenet_probe(struct platfor
|
||||
@@ -3508,14 +3509,15 @@ static int bcmgenet_probe(struct platfor
|
||||
}
|
||||
|
||||
if (dn) {
|
||||
@@ -1865,7 +1865,7 @@ Signed-off-by: David S. Miller <davem@davemloft.net>
|
||||
}
|
||||
|
||||
priv->base = devm_platform_ioremap_resource(pdev, 0);
|
||||
@@ -3517,7 +3519,6 @@ static int bcmgenet_probe(struct platfor
|
||||
@@ -3529,7 +3531,6 @@ static int bcmgenet_probe(struct platfor
|
||||
|
||||
SET_NETDEV_DEV(dev, &pdev->dev);
|
||||
dev_set_drvdata(&pdev->dev, dev);
|
||||
|
@@ -1,10 +1,6 @@
|
||||
diff --git a/crypto/asymmetric_keys/Kconfig b/crypto/asymmetric_keys/Kconfig
|
||||
index 59ec726b7c77..3f089abd6fc9 100644
|
||||
--- a/crypto/asymmetric_keys/Kconfig
|
||||
+++ b/crypto/asymmetric_keys/Kconfig
|
||||
@@ -13,10 +13,11 @@ if ASYMMETRIC_KEY_TYPE
|
||||
config ASYMMETRIC_PUBLIC_KEY_SUBTYPE
|
||||
tristate "Asymmetric public-key crypto algorithm subtype"
|
||||
@@ -15,6 +15,7 @@ config ASYMMETRIC_PUBLIC_KEY_SUBTYPE
|
||||
select MPILIB
|
||||
select CRYPTO_HASH_INFO
|
||||
select CRYPTO_AKCIPHER
|
||||
@@ -12,5 +8,3 @@ index 59ec726b7c77..3f089abd6fc9 100644
|
||||
select CRYPTO_HASH
|
||||
help
|
||||
This option provides support for asymmetric public key type handling.
|
||||
If signature generation and/or verification are to be used,
|
||||
appropriate hash algorithms (such as SHA-1) must be available.
|
||||
|
@@ -37,7 +37,7 @@
|
||||
* CONFIG_CMDLINE is meant to be a default in case nothing else
|
||||
--- a/arch/arm64/Kconfig
|
||||
+++ b/arch/arm64/Kconfig
|
||||
@@ -2240,6 +2240,14 @@ config CMDLINE_FORCE
|
||||
@@ -2239,6 +2239,14 @@ config CMDLINE_FORCE
|
||||
|
||||
endchoice
|
||||
|
||||
|
@@ -7,9 +7,11 @@ board_config_update
|
||||
board=$(board_name)
|
||||
|
||||
case "$board" in
|
||||
qnap,qhora-321|\
|
||||
iei,puzzle-m901)
|
||||
ucidef_set_led_netdev "wan" "WAN" "white:network" "eth0" "link"
|
||||
;;
|
||||
qnap,qhora-322|\
|
||||
iei,puzzle-m902)
|
||||
ucidef_set_led_netdev "wan" "WAN" "white:network" "eth2" "link"
|
||||
;;
|
||||
|
@@ -13,9 +13,11 @@ case "$board" in
|
||||
globalscale,mochabin)
|
||||
ucidef_set_interfaces_lan_wan "lan0 lan1 lan2 lan3" "eth0 eth2"
|
||||
;;
|
||||
qnap,qhora-321|\
|
||||
iei,puzzle-m901)
|
||||
ucidef_set_interfaces_lan_wan "eth1 eth2 eth3 eth4 eth5" "eth0"
|
||||
;;
|
||||
qnap,qhora-322|\
|
||||
iei,puzzle-m902)
|
||||
ucidef_set_interfaces_lan_wan "eth0 eth1 eth3 eth4 eth5 eth6 eth7 eth8" "eth2"
|
||||
;;
|
||||
|
@@ -31,6 +31,8 @@ platform_do_upgrade_emmc() {
|
||||
|
||||
v "Writing new UUID to /dev/$diskdev..."
|
||||
get_image_dd "$1" of="/dev/$diskdev" bs=1 skip=440 count=4 seek=440 conv=fsync
|
||||
|
||||
mkfs.ext4 -F -L rootfs_data $(find_mmc_part rootfs_data)
|
||||
|
||||
sleep 1
|
||||
}
|
||||
|
@@ -10,6 +10,8 @@ REQUIRE_IMAGE_METADATA=1
|
||||
platform_check_image() {
|
||||
case "$(board_name)" in
|
||||
globalscale,mochabin|\
|
||||
qnap,qhora-321|\
|
||||
qnap,qhora-322|\
|
||||
iei,puzzle-m901|\
|
||||
iei,puzzle-m902|\
|
||||
marvell,armada8040-mcbin-doubleshot|\
|
||||
@@ -25,6 +27,8 @@ platform_check_image() {
|
||||
|
||||
platform_do_upgrade() {
|
||||
case "$(board_name)" in
|
||||
qnap,qhora-321|\
|
||||
qnap,qhora-322|\
|
||||
iei,puzzle-m901|\
|
||||
iei,puzzle-m902)
|
||||
platform_do_upgrade_emmc "$1"
|
||||
@@ -43,6 +47,8 @@ platform_do_upgrade() {
|
||||
platform_copy_config() {
|
||||
case "$(board_name)" in
|
||||
globalscale,mochabin|\
|
||||
qnap,qhora-321|\
|
||||
qnap,qhora-322|\
|
||||
iei,puzzle-m901|\
|
||||
iei,puzzle-m902|\
|
||||
marvell,armada8040-mcbin-doubleshot|\
|
||||
|
@@ -0,0 +1,404 @@
|
||||
// SPDX-License-Identifier: (GPL-2.0-or-later OR MIT)
|
||||
/*
|
||||
* Copyright (C) 2019 Marvell International Ltd.
|
||||
*
|
||||
* Device tree for the CN9131-DB board.
|
||||
*/
|
||||
|
||||
#include "cn9130.dtsi"
|
||||
|
||||
#include <dt-bindings/gpio/gpio.h>
|
||||
#include <dt-bindings/input/input.h>
|
||||
|
||||
/ {
|
||||
model = "QNAP QHora-321";
|
||||
compatible = "qnap,qhora-321",
|
||||
"marvell,armada-ap807-quad", "marvell,armada-ap807";
|
||||
|
||||
chosen {
|
||||
stdout-path = "serial0:115200n8";
|
||||
bootargs-append = " root=/dev/mmcblk0p3";
|
||||
};
|
||||
|
||||
aliases {
|
||||
i2c0 = &cp1_i2c0;
|
||||
i2c1 = &cp0_i2c0;
|
||||
ethernet0 = &cp0_eth0;
|
||||
ethernet1 = &cp0_eth1;
|
||||
ethernet2 = &cp0_eth2;
|
||||
ethernet3 = &cp1_eth0;
|
||||
ethernet4 = &cp1_eth1;
|
||||
ethernet5 = &cp1_eth2;
|
||||
gpio1 = &cp0_gpio1;
|
||||
gpio2 = &cp0_gpio2;
|
||||
gpio3 = &cp1_gpio1;
|
||||
gpio4 = &cp1_gpio2;
|
||||
led-boot = &led_power;
|
||||
led-failsafe = &led_info;
|
||||
led-running = &led_power;
|
||||
led-upgrade = &led_info;
|
||||
};
|
||||
|
||||
memory@00000000 {
|
||||
device_type = "memory";
|
||||
reg = <0x0 0x0 0x0 0x80000000>;
|
||||
};
|
||||
|
||||
gpio_keys {
|
||||
compatible = "gpio-keys";
|
||||
|
||||
reset {
|
||||
label = "Reset";
|
||||
linux,code = <KEY_RESTART>;
|
||||
gpios = <&cp0_gpio2 4 GPIO_ACTIVE_LOW>;
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
&uart0 {
|
||||
status = "okay";
|
||||
};
|
||||
|
||||
&cp0_uart0 {
|
||||
status = "okay";
|
||||
|
||||
puzzle-mcu {
|
||||
compatible = "iei,wt61p803-puzzle";
|
||||
#address-cells = <1>;
|
||||
#size-cells = <1>;
|
||||
current-speed = <115200>;
|
||||
enable-beep;
|
||||
status = "okay";
|
||||
|
||||
leds {
|
||||
compatible = "iei,wt61p803-puzzle-leds";
|
||||
#address-cells = <1>;
|
||||
#size-cells = <0>;
|
||||
status = "okay";
|
||||
|
||||
led@0 {
|
||||
reg = <0>;
|
||||
label = "white:network";
|
||||
active-low;
|
||||
};
|
||||
|
||||
led@1 {
|
||||
reg = <1>;
|
||||
label = "green:cloud";
|
||||
active-low;
|
||||
};
|
||||
|
||||
led_info: led@2 {
|
||||
reg = <2>;
|
||||
label = "orange:info";
|
||||
active-low;
|
||||
};
|
||||
|
||||
led_power: led@3 {
|
||||
reg = <3>;
|
||||
label = "yellow:power";
|
||||
active-low;
|
||||
default-state = "on";
|
||||
};
|
||||
};
|
||||
|
||||
hwmon {
|
||||
compatible = "iei,wt61p803-puzzle-hwmon";
|
||||
#address-cells = <1>;
|
||||
#size-cells = <0>;
|
||||
|
||||
chassis_fan_group0: fan-group@0 {
|
||||
#cooling-cells = <2>;
|
||||
reg = <0x00>;
|
||||
cooling-levels = <64 102 170 230 250>;
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
&ap_thermal_cpu1 {
|
||||
trips {
|
||||
cpu_active: cpu-active {
|
||||
temperature = <44000>;
|
||||
hysteresis = <2000>;
|
||||
type = "active";
|
||||
};
|
||||
};
|
||||
cooling-maps {
|
||||
fan-map {
|
||||
trip = <&cpu_active>;
|
||||
cooling-device = <&chassis_fan_group0 64 THERMAL_NO_LIMIT>;
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
/* on-board eMMC - U9 */
|
||||
&ap_sdhci0 {
|
||||
pinctrl-names = "default";
|
||||
bus-width = <8>;
|
||||
status = "okay";
|
||||
mmc-ddr-1_8v;
|
||||
mmc-hs400-1_8v;
|
||||
};
|
||||
|
||||
&cp0_crypto {
|
||||
status = "okay";
|
||||
};
|
||||
|
||||
&cp0_xmdio {
|
||||
status = "okay";
|
||||
cp0_nbaset_phy0: ethernet-phy@0 {
|
||||
compatible = "ethernet-phy-ieee802.3-c45";
|
||||
reg = <2>;
|
||||
};
|
||||
cp0_nbaset_phy1: ethernet-phy@1 {
|
||||
compatible = "ethernet-phy-ieee802.3-c45";
|
||||
reg = <0>;
|
||||
};
|
||||
cp0_nbaset_phy2: ethernet-phy@2 {
|
||||
compatible = "ethernet-phy-ieee802.3-c45";
|
||||
reg = <8>;
|
||||
};
|
||||
};
|
||||
|
||||
&cp0_ethernet {
|
||||
status = "okay";
|
||||
};
|
||||
|
||||
/* SLM-1521-V2, CON9 */
|
||||
&cp0_eth0 {
|
||||
status = "okay";
|
||||
phy-mode = "2500base-x";
|
||||
phys = <&cp0_comphy2 0>;
|
||||
phy = <&cp0_nbaset_phy0>;
|
||||
};
|
||||
|
||||
&cp0_eth1 {
|
||||
status = "okay";
|
||||
phy-mode = "2500base-x";
|
||||
phys = <&cp0_comphy4 1>;
|
||||
phy = <&cp0_nbaset_phy1>;
|
||||
};
|
||||
|
||||
&cp0_eth2 {
|
||||
status = "okay";
|
||||
phy-mode = "2500base-x";
|
||||
phys = <&cp0_comphy5 2>;
|
||||
phy = <&cp0_nbaset_phy2>;
|
||||
};
|
||||
|
||||
&cp0_gpio1 {
|
||||
status = "okay";
|
||||
};
|
||||
|
||||
&cp0_gpio2 {
|
||||
status = "okay";
|
||||
};
|
||||
|
||||
&cp0_i2c0 {
|
||||
pinctrl-names = "default";
|
||||
pinctrl-0 = <&cp0_i2c0_pins>;
|
||||
status = "okay";
|
||||
clock-frequency = <100000>;
|
||||
rtc@32 {
|
||||
compatible = "epson,rx8130";
|
||||
reg = <0x32>;
|
||||
wakeup-source;
|
||||
};
|
||||
};
|
||||
|
||||
/* SLM-1521-V2, CON6 */
|
||||
&cp0_pcie0 {
|
||||
status = "okay";
|
||||
num-lanes = <2>;
|
||||
num-viewport = <8>;
|
||||
phys = <&cp0_comphy0 0>, <&cp0_comphy1 0>;
|
||||
};
|
||||
|
||||
/* U55 */
|
||||
&cp0_spi1 {
|
||||
pinctrl-names = "default";
|
||||
pinctrl-0 = <&cp0_spi0_pins>;
|
||||
reg = <0x700680 0x50>, /* control */
|
||||
<0x2000000 0x1000000>; /* CS0 */
|
||||
status = "okay";
|
||||
spi-flash@0 {
|
||||
#address-cells = <0x1>;
|
||||
#size-cells = <0x1>;
|
||||
compatible = "jedec,spi-nor";
|
||||
reg = <0x0>;
|
||||
spi-max-frequency = <40000000>;
|
||||
partitions {
|
||||
compatible = "fixed-partitions";
|
||||
#address-cells = <1>;
|
||||
#size-cells = <1>;
|
||||
partition@0 {
|
||||
label = "U-Boot";
|
||||
reg = <0x0 0x1f0000>;
|
||||
};
|
||||
partition@1f0000 {
|
||||
label = "U-Boot ENV Factory";
|
||||
reg = <0x1f0000 0x10000>;
|
||||
};
|
||||
partition@200000 {
|
||||
label = "Reserved";
|
||||
reg = <0x200000 0x1f0000>;
|
||||
};
|
||||
partition@3f0000 {
|
||||
label = "U-Boot ENV";
|
||||
reg = <0x3f0000 0x10000>;
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
&cp0_syscon0 {
|
||||
cp0_pinctrl: pinctrl {
|
||||
compatible = "marvell,cp115-standalone-pinctrl";
|
||||
cp0_i2c0_pins: cp0-i2c-pins-0 {
|
||||
marvell,pins = "mpp37", "mpp38";
|
||||
marvell,function = "i2c0";
|
||||
};
|
||||
cp0_i2c1_pins: cp0-i2c-pins-1 {
|
||||
marvell,pins = "mpp35", "mpp36";
|
||||
marvell,function = "i2c1";
|
||||
};
|
||||
cp0_ge1_rgmii_pins: cp0-ge-rgmii-pins-0 {
|
||||
marvell,pins = "mpp0", "mpp1", "mpp2",
|
||||
"mpp3", "mpp4", "mpp5",
|
||||
"mpp6", "mpp7", "mpp8",
|
||||
"mpp9", "mpp10", "mpp11";
|
||||
marvell,function = "ge0";
|
||||
};
|
||||
cp0_ge2_rgmii_pins: cp0-ge-rgmii-pins-1 {
|
||||
marvell,pins = "mpp44", "mpp45", "mpp46",
|
||||
"mpp47", "mpp48", "mpp49",
|
||||
"mpp50", "mpp51", "mpp52",
|
||||
"mpp53", "mpp54", "mpp55";
|
||||
marvell,function = "ge1";
|
||||
};
|
||||
cp0_spi0_pins: cp0-spi-pins-0 {
|
||||
marvell,pins = "mpp13", "mpp14", "mpp15", "mpp16";
|
||||
marvell,function = "spi1";
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
/*
|
||||
* Instantiate the first connected CP115
|
||||
*/
|
||||
|
||||
#define CP11X_NAME cp1
|
||||
#define CP11X_BASE f6000000
|
||||
#define CP11X_PCIEx_MEM_BASE(iface) (0xe2000000 + (iface * 0x1000000))
|
||||
#define CP11X_PCIEx_MEM_SIZE(iface) 0xf00000
|
||||
#define CP11X_PCIE0_BASE f6600000
|
||||
#define CP11X_PCIE1_BASE f6620000
|
||||
#define CP11X_PCIE2_BASE f6640000
|
||||
|
||||
#include "armada-cp115.dtsi"
|
||||
|
||||
#undef CP11X_NAME
|
||||
#undef CP11X_BASE
|
||||
#undef CP11X_PCIEx_MEM_BASE
|
||||
#undef CP11X_PCIEx_MEM_SIZE
|
||||
#undef CP11X_PCIE0_BASE
|
||||
#undef CP11X_PCIE1_BASE
|
||||
#undef CP11X_PCIE2_BASE
|
||||
|
||||
&cp1_crypto {
|
||||
status = "okay";
|
||||
};
|
||||
|
||||
&cp1_xmdio {
|
||||
status = "okay";
|
||||
cp1_nbaset_phy0: ethernet-phy@3 {
|
||||
compatible = "ethernet-phy-ieee802.3-c45";
|
||||
reg = <2>;
|
||||
};
|
||||
cp1_nbaset_phy1: ethernet-phy@4 {
|
||||
compatible = "ethernet-phy-ieee802.3-c45";
|
||||
reg = <0>;
|
||||
};
|
||||
cp1_nbaset_phy2: ethernet-phy@5 {
|
||||
compatible = "ethernet-phy-ieee802.3-c45";
|
||||
reg = <8>;
|
||||
};
|
||||
};
|
||||
|
||||
&cp1_ethernet {
|
||||
status = "okay";
|
||||
};
|
||||
|
||||
/* CON50 */
|
||||
&cp1_eth0 {
|
||||
status = "okay";
|
||||
phy-mode = "2500base-x";
|
||||
phys = <&cp1_comphy2 0>;
|
||||
phy = <&cp1_nbaset_phy0>;
|
||||
};
|
||||
|
||||
&cp1_eth1 {
|
||||
status = "okay";
|
||||
phy-mode = "2500base-x";
|
||||
phys = <&cp1_comphy4 1>;
|
||||
phy = <&cp1_nbaset_phy1>;
|
||||
};
|
||||
|
||||
&cp1_eth2 {
|
||||
status = "okay";
|
||||
phy-mode = "2500base-x";
|
||||
phys = <&cp1_comphy5 2>;
|
||||
phy = <&cp1_nbaset_phy2>;
|
||||
};
|
||||
|
||||
&cp1_sata0 {
|
||||
status = "okay";
|
||||
sata-port@1 {
|
||||
status = "okay";
|
||||
phys = <&cp1_comphy0 1>;
|
||||
};
|
||||
};
|
||||
|
||||
&cp1_gpio1 {
|
||||
status = "okay";
|
||||
};
|
||||
|
||||
&cp1_gpio2 {
|
||||
status = "okay";
|
||||
};
|
||||
|
||||
&cp1_i2c0 {
|
||||
status = "okay";
|
||||
pinctrl-names = "default";
|
||||
pinctrl-0 = <&cp1_i2c0_pins>;
|
||||
clock-frequency = <100000>;
|
||||
};
|
||||
|
||||
&cp1_syscon0 {
|
||||
cp1_pinctrl: pinctrl {
|
||||
compatible = "marvell,cp115-standalone-pinctrl";
|
||||
cp1_i2c0_pins: cp1-i2c-pins-0 {
|
||||
marvell,pins = "mpp37", "mpp38";
|
||||
marvell,function = "i2c0";
|
||||
};
|
||||
cp1_spi0_pins: cp1-spi-pins-0 {
|
||||
marvell,pins = "mpp13", "mpp14", "mpp15", "mpp16";
|
||||
marvell,function = "spi1";
|
||||
};
|
||||
cp1_xhci0_vbus_pins: cp1-xhci0-vbus-pins {
|
||||
marvell,pins = "mpp3";
|
||||
marvell,function = "gpio";
|
||||
};
|
||||
cp1_sfp_pins: sfp-pins {
|
||||
marvell,pins = "mpp8", "mpp9", "mpp10", "mpp11";
|
||||
marvell,function = "gpio";
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
&cp1_usb3_1 {
|
||||
status = "okay";
|
||||
phys = <&cp1_comphy3 1>;
|
||||
phy-names = "usb";
|
||||
};
|
@@ -17,6 +17,7 @@
|
||||
|
||||
chosen {
|
||||
stdout-path = "serial0:115200n8";
|
||||
bootargs-append = " root=/dev/mmcblk0p3";
|
||||
};
|
||||
|
||||
aliases {
|
||||
|
@@ -0,0 +1,565 @@
|
||||
// SPDX-License-Identifier: (GPL-2.0-or-later OR MIT)
|
||||
/*
|
||||
* Copyright (C) 2019 Marvell International Ltd.
|
||||
*
|
||||
* Device tree for the CN9132-DB board.
|
||||
*/
|
||||
|
||||
#include "cn9130.dtsi"
|
||||
|
||||
#include <dt-bindings/gpio/gpio.h>
|
||||
#include <dt-bindings/input/input.h>
|
||||
|
||||
/ {
|
||||
model = "QNAP QHora-322";
|
||||
compatible = "qnap,qhora-322",
|
||||
"marvell,armada-ap807-quad", "marvell,armada-ap807";
|
||||
|
||||
chosen {
|
||||
stdout-path = "serial0:115200n8";
|
||||
bootargs-append = " root=/dev/mmcblk0p3";
|
||||
};
|
||||
|
||||
aliases {
|
||||
i2c0 = &cp1_i2c0;
|
||||
i2c1 = &cp0_i2c0;
|
||||
gpio1 = &cp0_gpio1;
|
||||
gpio2 = &cp0_gpio2;
|
||||
gpio3 = &cp1_gpio1;
|
||||
gpio4 = &cp1_gpio2;
|
||||
gpio5 = &cp2_gpio1;
|
||||
gpio6 = &cp2_gpio2;
|
||||
ethernet0 = &cp0_eth0;
|
||||
ethernet1 = &cp0_eth1;
|
||||
ethernet2 = &cp0_eth2;
|
||||
ethernet3 = &cp1_eth0;
|
||||
ethernet4 = &cp1_eth1;
|
||||
ethernet5 = &cp1_eth2;
|
||||
ethernet6 = &cp2_eth0;
|
||||
ethernet7 = &cp2_eth1;
|
||||
ethernet8 = &cp2_eth2;
|
||||
spi1 = &cp0_spi0;
|
||||
spi2 = &cp0_spi1;
|
||||
led-boot = &led_power;
|
||||
led-failsafe = &led_info;
|
||||
led-running = &led_power;
|
||||
led-upgrade = &led_info;
|
||||
};
|
||||
|
||||
memory@00000000 {
|
||||
device_type = "memory";
|
||||
reg = <0x0 0x0 0x0 0x80000000>;
|
||||
};
|
||||
|
||||
gpio_keys {
|
||||
compatible = "gpio-keys";
|
||||
|
||||
reset {
|
||||
label = "Reset";
|
||||
linux,code = <KEY_RESTART>;
|
||||
gpios = <&cp0_gpio2 4 GPIO_ACTIVE_LOW>;
|
||||
};
|
||||
};
|
||||
|
||||
cp2_reg_usb3_vbus0: cp2_usb3_vbus@0 {
|
||||
compatible = "regulator-fixed";
|
||||
regulator-name = "cp2-xhci0-vbus";
|
||||
regulator-min-microvolt = <5000000>;
|
||||
regulator-max-microvolt = <5000000>;
|
||||
enable-active-high;
|
||||
gpio = <&cp2_gpio1 2 GPIO_ACTIVE_HIGH>;
|
||||
};
|
||||
|
||||
cp2_usb3_0_phy0: cp2_usb3_phy0 {
|
||||
compatible = "usb-nop-xceiv";
|
||||
vcc-supply = <&cp2_reg_usb3_vbus0>;
|
||||
};
|
||||
|
||||
cp2_reg_usb3_vbus1: cp2_usb3_vbus@1 {
|
||||
compatible = "regulator-fixed";
|
||||
regulator-name = "cp2-xhci1-vbus";
|
||||
regulator-min-microvolt = <5000000>;
|
||||
regulator-max-microvolt = <5000000>;
|
||||
enable-active-high;
|
||||
gpio = <&cp2_gpio1 3 GPIO_ACTIVE_HIGH>;
|
||||
};
|
||||
|
||||
cp2_usb3_0_phy1: cp2_usb3_phy1 {
|
||||
compatible = "usb-nop-xceiv";
|
||||
vcc-supply = <&cp2_reg_usb3_vbus1>;
|
||||
};
|
||||
|
||||
cp2_sfp_eth0: sfp-eth0 {
|
||||
compatible = "sff,sfp";
|
||||
i2c-bus = <&cp2_sfpp0_i2c>;
|
||||
los-gpio = <&cp2_module_expander1 11 GPIO_ACTIVE_HIGH>;
|
||||
mod-def0-gpio = <&cp2_module_expander1 10 GPIO_ACTIVE_LOW>;
|
||||
tx-disable-gpio = <&cp2_module_expander1 9 GPIO_ACTIVE_HIGH>;
|
||||
tx-fault-gpio = <&cp2_module_expander1 8 GPIO_ACTIVE_HIGH>;
|
||||
status = "disabled";
|
||||
};
|
||||
};
|
||||
|
||||
&uart0 {
|
||||
status = "okay";
|
||||
};
|
||||
|
||||
&cp0_uart0 {
|
||||
status = "okay";
|
||||
|
||||
puzzle-mcu {
|
||||
compatible = "iei,wt61p803-puzzle";
|
||||
#address-cells = <1>;
|
||||
#size-cells = <1>;
|
||||
current-speed = <115200>;
|
||||
enable-beep;
|
||||
status = "okay";
|
||||
|
||||
leds {
|
||||
compatible = "iei,wt61p803-puzzle-leds";
|
||||
#address-cells = <1>;
|
||||
#size-cells = <0>;
|
||||
status = "okay";
|
||||
|
||||
led@0 {
|
||||
reg = <0>;
|
||||
label = "white:network";
|
||||
active-low;
|
||||
};
|
||||
|
||||
led@1 {
|
||||
reg = <1>;
|
||||
label = "green:cloud";
|
||||
active-low;
|
||||
};
|
||||
|
||||
led_info: led@2 {
|
||||
reg = <2>;
|
||||
label = "orange:info";
|
||||
active-low;
|
||||
};
|
||||
|
||||
led_power: led@3 {
|
||||
reg = <3>;
|
||||
label = "yellow:power";
|
||||
active-low;
|
||||
default-state = "on";
|
||||
};
|
||||
};
|
||||
|
||||
hwmon {
|
||||
compatible = "iei,wt61p803-puzzle-hwmon";
|
||||
#address-cells = <1>;
|
||||
#size-cells = <0>;
|
||||
|
||||
chassis_fan_group0: fan-group@0 {
|
||||
#cooling-cells = <2>;
|
||||
reg = <0x00>;
|
||||
cooling-levels = <64 102 170 230 250>;
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
&ap_thermal_cpu1 {
|
||||
trips {
|
||||
cpu_active: cpu-active {
|
||||
temperature = <44000>;
|
||||
hysteresis = <2000>;
|
||||
type = "active";
|
||||
};
|
||||
};
|
||||
cooling-maps {
|
||||
fan-map {
|
||||
trip = <&cpu_active>;
|
||||
cooling-device = <&chassis_fan_group0 64 THERMAL_NO_LIMIT>;
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
/* on-board eMMC - U9 */
|
||||
&ap_sdhci0 {
|
||||
pinctrl-names = "default";
|
||||
bus-width = <8>;
|
||||
status = "okay";
|
||||
mmc-ddr-1_8v;
|
||||
mmc-hs400-1_8v;
|
||||
};
|
||||
|
||||
&cp0_crypto {
|
||||
status = "okay";
|
||||
};
|
||||
|
||||
&cp0_xmdio {
|
||||
status = "okay";
|
||||
cp0_nbaset_phy0: ethernet-phy@0 {
|
||||
compatible = "ethernet-phy-ieee802.3-c45";
|
||||
reg = <2>;
|
||||
};
|
||||
cp0_nbaset_phy1: ethernet-phy@1 {
|
||||
compatible = "ethernet-phy-ieee802.3-c45";
|
||||
reg = <0>;
|
||||
};
|
||||
cp0_nbaset_phy2: ethernet-phy@2 {
|
||||
compatible = "ethernet-phy-ieee802.3-c45";
|
||||
reg = <8>;
|
||||
};
|
||||
};
|
||||
|
||||
&cp0_ethernet {
|
||||
status = "okay";
|
||||
};
|
||||
|
||||
/* SLM-1521-V2, CON9 */
|
||||
&cp0_eth0 {
|
||||
status = "okay";
|
||||
phy-mode = "10gbase-kr";
|
||||
phys = <&cp0_comphy2 0>;
|
||||
phy = <&cp0_nbaset_phy0>;
|
||||
};
|
||||
|
||||
&cp0_eth1 {
|
||||
status = "okay";
|
||||
phy-mode = "2500base-x";
|
||||
phys = <&cp0_comphy4 1>;
|
||||
phy = <&cp0_nbaset_phy1>;
|
||||
};
|
||||
|
||||
&cp0_eth2 {
|
||||
status = "okay";
|
||||
phy-mode = "2500base-x";
|
||||
phys = <&cp0_comphy1 2>;
|
||||
phy = <&cp0_nbaset_phy2>;
|
||||
};
|
||||
|
||||
&cp0_gpio1 {
|
||||
status = "okay";
|
||||
};
|
||||
|
||||
&cp0_gpio2 {
|
||||
status = "okay";
|
||||
};
|
||||
|
||||
&cp0_i2c0 {
|
||||
pinctrl-names = "default";
|
||||
pinctrl-0 = <&cp0_i2c0_pins>;
|
||||
status = "okay";
|
||||
clock-frequency = <100000>;
|
||||
rtc@32 {
|
||||
compatible = "epson,rx8130";
|
||||
reg = <0x32>;
|
||||
wakeup-source;
|
||||
};
|
||||
};
|
||||
|
||||
&cp0_i2c1 {
|
||||
clock-frequency = <100000>;
|
||||
};
|
||||
|
||||
/* SLM-1521-V2, CON6 */
|
||||
&cp0_sata0 {
|
||||
status = "okay";
|
||||
sata-port@1 {
|
||||
status = "okay";
|
||||
phys = <&cp0_comphy0 1>;
|
||||
};
|
||||
};
|
||||
|
||||
&cp0_pcie2 {
|
||||
status = "okay";
|
||||
num-lanes = <1>;
|
||||
num-viewport = <8>;
|
||||
phys = <&cp0_comphy5 2>;
|
||||
};
|
||||
|
||||
/* U55 */
|
||||
&cp0_spi1 {
|
||||
pinctrl-names = "default";
|
||||
pinctrl-0 = <&cp0_spi0_pins>;
|
||||
reg = <0x700680 0x50>, /* control */
|
||||
<0x2000000 0x1000000>; /* CS0 */
|
||||
status = "okay";
|
||||
spi-flash@0 {
|
||||
#address-cells = <0x1>;
|
||||
#size-cells = <0x1>;
|
||||
compatible = "jedec,spi-nor";
|
||||
reg = <0x0>;
|
||||
spi-max-frequency = <40000000>;
|
||||
partitions {
|
||||
compatible = "fixed-partitions";
|
||||
#address-cells = <1>;
|
||||
#size-cells = <1>;
|
||||
partition@0 {
|
||||
label = "U-Boot";
|
||||
reg = <0x0 0x1f0000>;
|
||||
};
|
||||
partition@1f0000 {
|
||||
label = "U-Boot ENV Factory";
|
||||
reg = <0x1f0000 0x10000>;
|
||||
};
|
||||
partition@200000 {
|
||||
label = "Reserved";
|
||||
reg = <0x200000 0x1f0000>;
|
||||
};
|
||||
partition@3f0000 {
|
||||
label = "U-Boot ENV";
|
||||
reg = <0x3f0000 0x10000>;
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
&cp0_syscon0 {
|
||||
cp0_pinctrl: pinctrl {
|
||||
compatible = "marvell,cp115-standalone-pinctrl";
|
||||
cp0_i2c0_pins: cp0-i2c-pins-0 {
|
||||
marvell,pins = "mpp37", "mpp38";
|
||||
marvell,function = "i2c0";
|
||||
};
|
||||
cp0_i2c1_pins: cp0-i2c-pins-1 {
|
||||
marvell,pins = "mpp35", "mpp36";
|
||||
marvell,function = "i2c1";
|
||||
};
|
||||
cp0_ge1_rgmii_pins: cp0-ge-rgmii-pins-0 {
|
||||
marvell,pins = "mpp0", "mpp1", "mpp2",
|
||||
"mpp3", "mpp4", "mpp5",
|
||||
"mpp6", "mpp7", "mpp8",
|
||||
"mpp9", "mpp10", "mpp11";
|
||||
marvell,function = "ge0";
|
||||
};
|
||||
cp0_ge2_rgmii_pins: cp0-ge-rgmii-pins-1 {
|
||||
marvell,pins = "mpp44", "mpp45", "mpp46",
|
||||
"mpp47", "mpp48", "mpp49",
|
||||
"mpp50", "mpp51", "mpp52",
|
||||
"mpp53", "mpp54", "mpp55";
|
||||
marvell,function = "ge1";
|
||||
};
|
||||
cp0_spi0_pins: cp0-spi-pins-0 {
|
||||
marvell,pins = "mpp13", "mpp14", "mpp15", "mpp16";
|
||||
marvell,function = "spi1";
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
&cp0_usb3_1 {
|
||||
status = "okay";
|
||||
phys = <&cp0_comphy3 1>;
|
||||
phy-names = "usb";
|
||||
};
|
||||
|
||||
/*
|
||||
* Instantiate the first connected CP115
|
||||
*/
|
||||
|
||||
#define CP11X_NAME cp1
|
||||
#define CP11X_BASE f4000000
|
||||
#define CP11X_PCIEx_MEM_BASE(iface) (0xe2000000 + (iface * 0x1000000))
|
||||
#define CP11X_PCIEx_MEM_SIZE(iface) 0xf00000
|
||||
#define CP11X_PCIE0_BASE f4600000
|
||||
#define CP11X_PCIE1_BASE f4620000
|
||||
#define CP11X_PCIE2_BASE f4640000
|
||||
|
||||
#include "armada-cp115.dtsi"
|
||||
|
||||
#undef CP11X_NAME
|
||||
#undef CP11X_BASE
|
||||
#undef CP11X_PCIEx_MEM_BASE
|
||||
#undef CP11X_PCIEx_MEM_SIZE
|
||||
#undef CP11X_PCIE0_BASE
|
||||
#undef CP11X_PCIE1_BASE
|
||||
#undef CP11X_PCIE2_BASE
|
||||
|
||||
&cp1_crypto {
|
||||
status = "okay";
|
||||
};
|
||||
|
||||
&cp1_xmdio {
|
||||
status = "okay";
|
||||
cp1_nbaset_phy0: ethernet-phy@3 {
|
||||
compatible = "ethernet-phy-ieee802.3-c45";
|
||||
reg = <2>;
|
||||
};
|
||||
cp1_nbaset_phy1: ethernet-phy@4 {
|
||||
compatible = "ethernet-phy-ieee802.3-c45";
|
||||
reg = <0>;
|
||||
};
|
||||
cp1_nbaset_phy2: ethernet-phy@5 {
|
||||
compatible = "ethernet-phy-ieee802.3-c45";
|
||||
reg = <8>;
|
||||
};
|
||||
};
|
||||
|
||||
&cp1_ethernet {
|
||||
status = "okay";
|
||||
};
|
||||
|
||||
/* CON50 */
|
||||
&cp1_eth0 {
|
||||
status = "okay";
|
||||
phy-mode = "10gbase-kr";
|
||||
phys = <&cp1_comphy2 0>;
|
||||
phy = <&cp1_nbaset_phy0>;
|
||||
};
|
||||
|
||||
&cp1_eth1 {
|
||||
status = "okay";
|
||||
phy-mode = "2500base-x";
|
||||
phys = <&cp1_comphy4 1>;
|
||||
phy = <&cp1_nbaset_phy1>;
|
||||
};
|
||||
|
||||
&cp1_eth2 {
|
||||
status = "okay";
|
||||
phy-mode = "2500base-x";
|
||||
phys = <&cp1_comphy1 2>;
|
||||
phy = <&cp1_nbaset_phy2>;
|
||||
};
|
||||
|
||||
&cp1_gpio1 {
|
||||
status = "okay";
|
||||
};
|
||||
|
||||
&cp1_gpio2 {
|
||||
status = "okay";
|
||||
};
|
||||
|
||||
&cp1_i2c0 {
|
||||
status = "okay";
|
||||
pinctrl-names = "default";
|
||||
pinctrl-0 = <&cp1_i2c0_pins>;
|
||||
clock-frequency = <100000>;
|
||||
};
|
||||
|
||||
&cp1_syscon0 {
|
||||
cp1_pinctrl: pinctrl {
|
||||
compatible = "marvell,cp115-standalone-pinctrl";
|
||||
cp1_i2c0_pins: cp1-i2c-pins-0 {
|
||||
marvell,pins = "mpp37", "mpp38";
|
||||
marvell,function = "i2c0";
|
||||
};
|
||||
cp1_spi0_pins: cp1-spi-pins-0 {
|
||||
marvell,pins = "mpp13", "mpp14", "mpp15", "mpp16";
|
||||
marvell,function = "spi1";
|
||||
};
|
||||
cp1_xhci0_vbus_pins: cp1-xhci0-vbus-pins {
|
||||
marvell,pins = "mpp3";
|
||||
marvell,function = "gpio";
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
/*
|
||||
* Instantiate the second connected CP115
|
||||
*/
|
||||
|
||||
#define CP11X_NAME cp2
|
||||
#define CP11X_BASE f6000000
|
||||
#define CP11X_PCIEx_MEM_BASE(iface) (0xe5000000 + (iface * 0x1000000))
|
||||
#define CP11X_PCIEx_MEM_SIZE(iface) 0xf00000
|
||||
#define CP11X_PCIE0_BASE f6600000
|
||||
#define CP11X_PCIE1_BASE f6620000
|
||||
#define CP11X_PCIE2_BASE f6640000
|
||||
|
||||
#include "armada-cp115.dtsi"
|
||||
|
||||
#undef CP11X_NAME
|
||||
#undef CP11X_BASE
|
||||
#undef CP11X_PCIEx_MEM_BASE
|
||||
#undef CP11X_PCIEx_MEM_SIZE
|
||||
#undef CP11X_PCIE0_BASE
|
||||
#undef CP11X_PCIE1_BASE
|
||||
#undef CP11X_PCIE2_BASE
|
||||
|
||||
&cp2_crypto {
|
||||
status = "okay";
|
||||
};
|
||||
|
||||
&cp2_ethernet {
|
||||
status = "okay";
|
||||
};
|
||||
|
||||
&cp2_xmdio {
|
||||
status = "okay";
|
||||
cp2_nbaset_phy0: ethernet-phy@6 {
|
||||
compatible = "ethernet-phy-ieee802.3-c45";
|
||||
reg = <2>;
|
||||
};
|
||||
cp2_nbaset_phy1: ethernet-phy@7 {
|
||||
compatible = "ethernet-phy-ieee802.3-c45";
|
||||
reg = <0>;
|
||||
};
|
||||
cp2_nbaset_phy2: ethernet-phy@8 {
|
||||
compatible = "ethernet-phy-ieee802.3-c45";
|
||||
reg = <8>;
|
||||
};
|
||||
};
|
||||
|
||||
/* SLM-1521-V2, CON9 */
|
||||
&cp2_eth0 {
|
||||
status = "okay";
|
||||
phy-mode = "10gbase-kr";
|
||||
phys = <&cp2_comphy2 0>;
|
||||
phy = <&cp2_nbaset_phy0>;
|
||||
};
|
||||
|
||||
&cp2_eth1 {
|
||||
status = "okay";
|
||||
phy-mode = "2500base-x";
|
||||
phys = <&cp2_comphy4 1>;
|
||||
phy = <&cp2_nbaset_phy1>;
|
||||
};
|
||||
|
||||
&cp2_eth2 {
|
||||
status = "okay";
|
||||
phy-mode = "2500base-x";
|
||||
phys = <&cp2_comphy1 2>;
|
||||
phy = <&cp2_nbaset_phy2>;
|
||||
};
|
||||
|
||||
&cp2_gpio1 {
|
||||
status = "okay";
|
||||
};
|
||||
|
||||
&cp2_gpio2 {
|
||||
status = "okay";
|
||||
};
|
||||
|
||||
&cp2_i2c0 {
|
||||
clock-frequency = <100000>;
|
||||
/* SLM-1521-V2 - U3 */
|
||||
i2c-mux@72 {
|
||||
compatible = "nxp,pca9544";
|
||||
#address-cells = <1>;
|
||||
#size-cells = <0>;
|
||||
reg = <0x72>;
|
||||
cp2_sfpp0_i2c: i2c@0 {
|
||||
#address-cells = <1>;
|
||||
#size-cells = <0>;
|
||||
reg = <0>;
|
||||
};
|
||||
|
||||
i2c@1 {
|
||||
#address-cells = <1>;
|
||||
#size-cells = <0>;
|
||||
reg = <1>;
|
||||
/* U12 */
|
||||
cp2_module_expander1: pca9555@21 {
|
||||
compatible = "nxp,pca9555";
|
||||
pinctrl-names = "default";
|
||||
gpio-controller;
|
||||
#gpio-cells = <2>;
|
||||
reg = <0x21>;
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
&cp2_syscon0 {
|
||||
cp2_pinctrl: pinctrl {
|
||||
compatible = "marvell,cp115-standalone-pinctrl";
|
||||
cp2_i2c0_pins: cp2-i2c-pins-0 {
|
||||
marvell,pins = "mpp37", "mpp38";
|
||||
marvell,function = "i2c0";
|
||||
};
|
||||
};
|
||||
};
|
@@ -17,6 +17,7 @@
|
||||
|
||||
chosen {
|
||||
stdout-path = "serial0:115200n8";
|
||||
bootargs-append = " root=/dev/mmcblk0p3";
|
||||
};
|
||||
|
||||
aliases {
|
||||
|
@@ -39,6 +39,16 @@ define Build/boot-img-ext4
|
||||
$@.bootimg $@.boot
|
||||
endef
|
||||
|
||||
define Build/boot-qnap-img-ext4
|
||||
rm -fR $@.boot
|
||||
mkdir -p $@.boot
|
||||
$(foreach dts,$(DEVICE_DTS), $(CP) $(KDIR)/image-$(dts).dtb $@.boot/$(dts).dtb;)
|
||||
$(CP) $(KDIR)/vmlinux $@.boot/Image
|
||||
make_ext4fs -J -L kernel -l $(CONFIG_TARGET_KERNEL_PARTSIZE)M \
|
||||
$(if $(SOURCE_DATE_EPOCH),-T $(SOURCE_DATE_EPOCH)) \
|
||||
$@.bootimg $@.boot
|
||||
endef
|
||||
|
||||
define Build/buffalo-kernel-jffs2
|
||||
rm -rf $(KDIR)/kernel_jffs2 $@.fakerd
|
||||
mkdir -p $(KDIR)/kernel_jffs2
|
||||
|
@@ -78,3 +78,15 @@ define Device/iei_puzzle-m902
|
||||
SOC := cn9132
|
||||
endef
|
||||
TARGET_DEVICES += iei_puzzle-m902
|
||||
|
||||
define Device/qnap_qhora-32x
|
||||
$(call Device/Default-arm64)
|
||||
SOC := cn9132
|
||||
DEVICE_VENDOR := QNAP
|
||||
DEVICE_MODEL := QHora-321/322
|
||||
DEVICE_PACKAGES += kmod-rtc-ds1307
|
||||
DEVICE_DTS := cn9131-db-A cn9131-puzzle-m901 cn9132-db-A cn9132-puzzle-m902
|
||||
SUPPORTED_DEVICES := qnap,qhora-321 qnap,qhora-322 iei,puzzle-m901 iei,puzzle-m902
|
||||
IMAGE/sdcard.img.gz := boot-scr | boot-qnap-img-ext4 | sdcard-img-ext4 | gzip | append-metadata
|
||||
endef
|
||||
TARGET_DEVICES += qnap_qhora-32x
|
||||
|
@@ -0,0 +1,25 @@
|
||||
From: David Bauer <mail@david-bauer.net>
|
||||
Date: Thu, 11 Feb 2021 19:57:26 +0100
|
||||
Subject: [PATCH] mtd: spi-nor: add support for Winbond W25Q512
|
||||
|
||||
The Winbond W25Q512 is a 512mb SPI-NOR chip. It supports 4K sectors as
|
||||
well as block protection and Dual-/Quad-read.
|
||||
|
||||
Tested on: Ubiquiti UniFi 6 LR
|
||||
|
||||
Signed-off-by: David Bauer <mail@david-bauer.net>
|
||||
|
||||
Ref: https://patchwork.ozlabs.org/project/linux-mtd/patch/20210213151047.11700-1-mail@david-bauer.net/
|
||||
|
||||
--- a/drivers/mtd/spi-nor/spi-nor.c
|
||||
+++ b/drivers/mtd/spi-nor/spi-nor.c
|
||||
@@ -2550,6 +2550,9 @@ static const struct flash_info spi_nor_i
|
||||
.fixups = &w25q256_fixups },
|
||||
{ "w25q256jvm", INFO(0xef7019, 0, 64 * 1024, 512,
|
||||
SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ) },
|
||||
+ { "w25q512jv", INFO(0xef4020, 0, 64 * 1024, 1024,
|
||||
+ SECT_4K | SPI_NOR_QUAD_READ | SPI_NOR_DUAL_READ |
|
||||
+ SPI_NOR_HAS_TB | SPI_NOR_HAS_LOCK) },
|
||||
{ "w25m512jv", INFO(0xef7119, 0, 64 * 1024, 1024,
|
||||
SECT_4K | SPI_NOR_QUAD_READ | SPI_NOR_DUAL_READ) },
|
||||
|
@@ -51,6 +51,13 @@ namespace Ryujinx.Graphics.GAL
|
||||
public readonly bool SupportsIndirectParameters;
|
||||
public readonly bool SupportsDepthClipControl;
|
||||
|
||||
public readonly int UniformBufferSetIndex;
|
||||
public readonly int StorageBufferSetIndex;
|
||||
public readonly int TextureSetIndex;
|
||||
public readonly int ImageSetIndex;
|
||||
public readonly int ExtraSetBaseIndex;
|
||||
public readonly int MaximumExtraSets;
|
||||
|
||||
public readonly uint MaximumUniformBuffersPerStage;
|
||||
public readonly uint MaximumStorageBuffersPerStage;
|
||||
public readonly uint MaximumTexturesPerStage;
|
||||
@@ -109,6 +116,12 @@ namespace Ryujinx.Graphics.GAL
|
||||
bool supportsViewportSwizzle,
|
||||
bool supportsIndirectParameters,
|
||||
bool supportsDepthClipControl,
|
||||
int uniformBufferSetIndex,
|
||||
int storageBufferSetIndex,
|
||||
int textureSetIndex,
|
||||
int imageSetIndex,
|
||||
int extraSetBaseIndex,
|
||||
int maximumExtraSets,
|
||||
uint maximumUniformBuffersPerStage,
|
||||
uint maximumStorageBuffersPerStage,
|
||||
uint maximumTexturesPerStage,
|
||||
@@ -164,6 +177,12 @@ namespace Ryujinx.Graphics.GAL
|
||||
SupportsViewportSwizzle = supportsViewportSwizzle;
|
||||
SupportsIndirectParameters = supportsIndirectParameters;
|
||||
SupportsDepthClipControl = supportsDepthClipControl;
|
||||
UniformBufferSetIndex = uniformBufferSetIndex;
|
||||
StorageBufferSetIndex = storageBufferSetIndex;
|
||||
TextureSetIndex = textureSetIndex;
|
||||
ImageSetIndex = imageSetIndex;
|
||||
ExtraSetBaseIndex = extraSetBaseIndex;
|
||||
MaximumExtraSets = maximumExtraSets;
|
||||
MaximumUniformBuffersPerStage = maximumUniformBuffersPerStage;
|
||||
MaximumStorageBuffersPerStage = maximumStorageBuffersPerStage;
|
||||
MaximumTexturesPerStage = maximumTexturesPerStage;
|
||||
|
@@ -60,6 +60,7 @@ namespace Ryujinx.Graphics.GAL
|
||||
|
||||
void SetImage(ShaderStage stage, int binding, ITexture texture, Format imageFormat);
|
||||
void SetImageArray(ShaderStage stage, int binding, IImageArray array);
|
||||
void SetImageArraySeparate(ShaderStage stage, int setIndex, IImageArray array);
|
||||
|
||||
void SetLineParameters(float width, bool smooth);
|
||||
|
||||
@@ -91,6 +92,7 @@ namespace Ryujinx.Graphics.GAL
|
||||
|
||||
void SetTextureAndSampler(ShaderStage stage, int binding, ITexture texture, ISampler sampler);
|
||||
void SetTextureArray(ShaderStage stage, int binding, ITextureArray array);
|
||||
void SetTextureArraySeparate(ShaderStage stage, int setIndex, ITextureArray array);
|
||||
|
||||
void SetTransformFeedbackBuffers(ReadOnlySpan<BufferRange> buffers);
|
||||
void SetUniformBuffers(ReadOnlySpan<BufferAssignment> buffers);
|
||||
|
@@ -124,6 +124,7 @@ namespace Ryujinx.Graphics.GAL.Multithreading
|
||||
Register<SetUniformBuffersCommand>(CommandType.SetUniformBuffers);
|
||||
Register<SetImageCommand>(CommandType.SetImage);
|
||||
Register<SetImageArrayCommand>(CommandType.SetImageArray);
|
||||
Register<SetImageArraySeparateCommand>(CommandType.SetImageArraySeparate);
|
||||
Register<SetIndexBufferCommand>(CommandType.SetIndexBuffer);
|
||||
Register<SetLineParametersCommand>(CommandType.SetLineParameters);
|
||||
Register<SetLogicOpStateCommand>(CommandType.SetLogicOpState);
|
||||
@@ -141,6 +142,7 @@ namespace Ryujinx.Graphics.GAL.Multithreading
|
||||
Register<SetStencilTestCommand>(CommandType.SetStencilTest);
|
||||
Register<SetTextureAndSamplerCommand>(CommandType.SetTextureAndSampler);
|
||||
Register<SetTextureArrayCommand>(CommandType.SetTextureArray);
|
||||
Register<SetTextureArraySeparateCommand>(CommandType.SetTextureArraySeparate);
|
||||
Register<SetUserClipDistanceCommand>(CommandType.SetUserClipDistance);
|
||||
Register<SetVertexAttribsCommand>(CommandType.SetVertexAttribs);
|
||||
Register<SetVertexBuffersCommand>(CommandType.SetVertexBuffers);
|
||||
|
@@ -84,6 +84,7 @@ namespace Ryujinx.Graphics.GAL.Multithreading
|
||||
SetUniformBuffers,
|
||||
SetImage,
|
||||
SetImageArray,
|
||||
SetImageArraySeparate,
|
||||
SetIndexBuffer,
|
||||
SetLineParameters,
|
||||
SetLogicOpState,
|
||||
@@ -101,6 +102,7 @@ namespace Ryujinx.Graphics.GAL.Multithreading
|
||||
SetStencilTest,
|
||||
SetTextureAndSampler,
|
||||
SetTextureArray,
|
||||
SetTextureArraySeparate,
|
||||
SetUserClipDistance,
|
||||
SetVertexAttribs,
|
||||
SetVertexBuffers,
|
||||
|
@@ -0,0 +1,26 @@
|
||||
using Ryujinx.Graphics.GAL.Multithreading.Model;
|
||||
using Ryujinx.Graphics.GAL.Multithreading.Resources;
|
||||
using Ryujinx.Graphics.Shader;
|
||||
|
||||
namespace Ryujinx.Graphics.GAL.Multithreading.Commands
|
||||
{
|
||||
struct SetImageArraySeparateCommand : IGALCommand, IGALCommand<SetImageArraySeparateCommand>
|
||||
{
|
||||
public readonly CommandType CommandType => CommandType.SetImageArraySeparate;
|
||||
private ShaderStage _stage;
|
||||
private int _setIndex;
|
||||
private TableRef<IImageArray> _array;
|
||||
|
||||
public void Set(ShaderStage stage, int setIndex, TableRef<IImageArray> array)
|
||||
{
|
||||
_stage = stage;
|
||||
_setIndex = setIndex;
|
||||
_array = array;
|
||||
}
|
||||
|
||||
public static void Run(ref SetImageArraySeparateCommand command, ThreadedRenderer threaded, IRenderer renderer)
|
||||
{
|
||||
renderer.Pipeline.SetImageArraySeparate(command._stage, command._setIndex, command._array.GetAs<ThreadedImageArray>(threaded)?.Base);
|
||||
}
|
||||
}
|
||||
}
|
@@ -0,0 +1,26 @@
|
||||
using Ryujinx.Graphics.GAL.Multithreading.Model;
|
||||
using Ryujinx.Graphics.GAL.Multithreading.Resources;
|
||||
using Ryujinx.Graphics.Shader;
|
||||
|
||||
namespace Ryujinx.Graphics.GAL.Multithreading.Commands
|
||||
{
|
||||
struct SetTextureArraySeparateCommand : IGALCommand, IGALCommand<SetTextureArraySeparateCommand>
|
||||
{
|
||||
public readonly CommandType CommandType => CommandType.SetTextureArraySeparate;
|
||||
private ShaderStage _stage;
|
||||
private int _setIndex;
|
||||
private TableRef<ITextureArray> _array;
|
||||
|
||||
public void Set(ShaderStage stage, int setIndex, TableRef<ITextureArray> array)
|
||||
{
|
||||
_stage = stage;
|
||||
_setIndex = setIndex;
|
||||
_array = array;
|
||||
}
|
||||
|
||||
public static void Run(ref SetTextureArraySeparateCommand command, ThreadedRenderer threaded, IRenderer renderer)
|
||||
{
|
||||
renderer.Pipeline.SetTextureArraySeparate(command._stage, command._setIndex, command._array.GetAs<ThreadedTextureArray>(threaded)?.Base);
|
||||
}
|
||||
}
|
||||
}
|
@@ -189,6 +189,12 @@ namespace Ryujinx.Graphics.GAL.Multithreading
|
||||
_renderer.QueueCommand();
|
||||
}
|
||||
|
||||
public void SetImageArraySeparate(ShaderStage stage, int setIndex, IImageArray array)
|
||||
{
|
||||
_renderer.New<SetImageArraySeparateCommand>().Set(stage, setIndex, Ref(array));
|
||||
_renderer.QueueCommand();
|
||||
}
|
||||
|
||||
public void SetIndexBuffer(BufferRange buffer, IndexType type)
|
||||
{
|
||||
_renderer.New<SetIndexBufferCommand>().Set(buffer, type);
|
||||
@@ -297,6 +303,12 @@ namespace Ryujinx.Graphics.GAL.Multithreading
|
||||
_renderer.QueueCommand();
|
||||
}
|
||||
|
||||
public void SetTextureArraySeparate(ShaderStage stage, int setIndex, ITextureArray array)
|
||||
{
|
||||
_renderer.New<SetTextureArraySeparateCommand>().Set(stage, setIndex, Ref(array));
|
||||
_renderer.QueueCommand();
|
||||
}
|
||||
|
||||
public void SetTransformFeedbackBuffers(ReadOnlySpan<BufferRange> buffers)
|
||||
{
|
||||
_renderer.New<SetTransformFeedbackBuffersCommand>().Set(_renderer.CopySpan(buffers));
|
||||
|
@@ -19,6 +19,11 @@ namespace Ryujinx.Graphics.Gpu.Image
|
||||
/// </summary>
|
||||
public Format Format { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Shader texture host set index.
|
||||
/// </summary>
|
||||
public int Set { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Shader texture host binding point.
|
||||
/// </summary>
|
||||
@@ -54,15 +59,17 @@ namespace Ryujinx.Graphics.Gpu.Image
|
||||
/// </summary>
|
||||
/// <param name="target">The shader sampler target type</param>
|
||||
/// <param name="format">Format of the image as declared on the shader</param>
|
||||
/// <param name="set">Shader texture host set index</param>
|
||||
/// <param name="binding">The shader texture binding point</param>
|
||||
/// <param name="arrayLength">For array of textures, this indicates the length of the array. A value of one indicates it is not an array</param>
|
||||
/// <param name="cbufSlot">Constant buffer slot where the texture handle is located</param>
|
||||
/// <param name="handle">The shader texture handle (read index into the texture constant buffer)</param>
|
||||
/// <param name="flags">The texture's usage flags, indicating how it is used in the shader</param>
|
||||
public TextureBindingInfo(Target target, Format format, int binding, int arrayLength, int cbufSlot, int handle, TextureUsageFlags flags)
|
||||
public TextureBindingInfo(Target target, Format format, int set, int binding, int arrayLength, int cbufSlot, int handle, TextureUsageFlags flags)
|
||||
{
|
||||
Target = target;
|
||||
Format = format;
|
||||
Set = set;
|
||||
Binding = binding;
|
||||
ArrayLength = arrayLength;
|
||||
CbufSlot = cbufSlot;
|
||||
@@ -74,6 +81,7 @@ namespace Ryujinx.Graphics.Gpu.Image
|
||||
/// Constructs the texture binding information structure.
|
||||
/// </summary>
|
||||
/// <param name="target">The shader sampler target type</param>
|
||||
/// <param name="set">Shader texture host set index</param>
|
||||
/// <param name="binding">The shader texture binding point</param>
|
||||
/// <param name="arrayLength">For array of textures, this indicates the length of the array. A value of one indicates it is not an array</param>
|
||||
/// <param name="cbufSlot">Constant buffer slot where the texture handle is located</param>
|
||||
@@ -82,12 +90,13 @@ namespace Ryujinx.Graphics.Gpu.Image
|
||||
/// <param name="isSamplerOnly">Indicates that the binding is for a sampler</param>
|
||||
public TextureBindingInfo(
|
||||
Target target,
|
||||
int set,
|
||||
int binding,
|
||||
int arrayLength,
|
||||
int cbufSlot,
|
||||
int handle,
|
||||
TextureUsageFlags flags,
|
||||
bool isSamplerOnly) : this(target, 0, binding, arrayLength, cbufSlot, handle, flags)
|
||||
bool isSamplerOnly) : this(target, 0, set, binding, arrayLength, cbufSlot, handle, flags)
|
||||
{
|
||||
IsSamplerOnly = isSamplerOnly;
|
||||
}
|
||||
|
@@ -566,7 +566,7 @@ namespace Ryujinx.Graphics.Gpu.Image
|
||||
int stageIndex,
|
||||
int textureBufferIndex,
|
||||
SamplerIndex samplerIndex,
|
||||
TextureBindingInfo bindingInfo)
|
||||
in TextureBindingInfo bindingInfo)
|
||||
{
|
||||
Update(texturePool, samplerPool, stage, stageIndex, textureBufferIndex, isImage: false, samplerIndex, bindingInfo);
|
||||
}
|
||||
@@ -579,7 +579,7 @@ namespace Ryujinx.Graphics.Gpu.Image
|
||||
/// <param name="stageIndex">Shader stage index where the array is used</param>
|
||||
/// <param name="textureBufferIndex">Texture constant buffer index</param>
|
||||
/// <param name="bindingInfo">Array binding information</param>
|
||||
public void UpdateImageArray(TexturePool texturePool, ShaderStage stage, int stageIndex, int textureBufferIndex, TextureBindingInfo bindingInfo)
|
||||
public void UpdateImageArray(TexturePool texturePool, ShaderStage stage, int stageIndex, int textureBufferIndex, in TextureBindingInfo bindingInfo)
|
||||
{
|
||||
Update(texturePool, null, stage, stageIndex, textureBufferIndex, isImage: true, SamplerIndex.ViaHeaderIndex, bindingInfo);
|
||||
}
|
||||
@@ -603,7 +603,7 @@ namespace Ryujinx.Graphics.Gpu.Image
|
||||
int textureBufferIndex,
|
||||
bool isImage,
|
||||
SamplerIndex samplerIndex,
|
||||
TextureBindingInfo bindingInfo)
|
||||
in TextureBindingInfo bindingInfo)
|
||||
{
|
||||
if (IsDirectHandleType(bindingInfo.Handle))
|
||||
{
|
||||
@@ -623,7 +623,7 @@ namespace Ryujinx.Graphics.Gpu.Image
|
||||
/// <param name="stage">Shader stage where the array is used</param>
|
||||
/// <param name="isImage">Whether the array is a image or texture array</param>
|
||||
/// <param name="bindingInfo">Array binding information</param>
|
||||
private void UpdateFromPool(TexturePool texturePool, SamplerPool samplerPool, ShaderStage stage, bool isImage, TextureBindingInfo bindingInfo)
|
||||
private void UpdateFromPool(TexturePool texturePool, SamplerPool samplerPool, ShaderStage stage, bool isImage, in TextureBindingInfo bindingInfo)
|
||||
{
|
||||
CacheEntry entry = GetOrAddEntry(texturePool, samplerPool, bindingInfo, isImage, out bool isNewEntry);
|
||||
|
||||
@@ -638,11 +638,11 @@ namespace Ryujinx.Graphics.Gpu.Image
|
||||
|
||||
if (isImage)
|
||||
{
|
||||
_context.Renderer.Pipeline.SetImageArray(stage, bindingInfo.Binding, entry.ImageArray);
|
||||
SetImageArray(stage, bindingInfo, entry.ImageArray);
|
||||
}
|
||||
else
|
||||
{
|
||||
_context.Renderer.Pipeline.SetTextureArray(stage, bindingInfo.Binding, entry.TextureArray);
|
||||
SetTextureArray(stage, bindingInfo, entry.TextureArray);
|
||||
}
|
||||
|
||||
return;
|
||||
@@ -737,14 +737,14 @@ namespace Ryujinx.Graphics.Gpu.Image
|
||||
entry.ImageArray.SetFormats(0, formats);
|
||||
entry.ImageArray.SetImages(0, textures);
|
||||
|
||||
_context.Renderer.Pipeline.SetImageArray(stage, bindingInfo.Binding, entry.ImageArray);
|
||||
SetImageArray(stage, bindingInfo, entry.ImageArray);
|
||||
}
|
||||
else
|
||||
{
|
||||
entry.TextureArray.SetSamplers(0, samplers);
|
||||
entry.TextureArray.SetTextures(0, textures);
|
||||
|
||||
_context.Renderer.Pipeline.SetTextureArray(stage, bindingInfo.Binding, entry.TextureArray);
|
||||
SetTextureArray(stage, bindingInfo, entry.TextureArray);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -767,7 +767,7 @@ namespace Ryujinx.Graphics.Gpu.Image
|
||||
int textureBufferIndex,
|
||||
bool isImage,
|
||||
SamplerIndex samplerIndex,
|
||||
TextureBindingInfo bindingInfo)
|
||||
in TextureBindingInfo bindingInfo)
|
||||
{
|
||||
(textureBufferIndex, int samplerBufferIndex) = TextureHandle.UnpackSlots(bindingInfo.CbufSlot, textureBufferIndex);
|
||||
|
||||
@@ -800,11 +800,11 @@ namespace Ryujinx.Graphics.Gpu.Image
|
||||
|
||||
if (isImage)
|
||||
{
|
||||
_context.Renderer.Pipeline.SetImageArray(stage, bindingInfo.Binding, entry.ImageArray);
|
||||
SetImageArray(stage, bindingInfo, entry.ImageArray);
|
||||
}
|
||||
else
|
||||
{
|
||||
_context.Renderer.Pipeline.SetTextureArray(stage, bindingInfo.Binding, entry.TextureArray);
|
||||
SetTextureArray(stage, bindingInfo, entry.TextureArray);
|
||||
}
|
||||
|
||||
return;
|
||||
@@ -829,11 +829,11 @@ namespace Ryujinx.Graphics.Gpu.Image
|
||||
|
||||
if (isImage)
|
||||
{
|
||||
_context.Renderer.Pipeline.SetImageArray(stage, bindingInfo.Binding, entry.ImageArray);
|
||||
SetImageArray(stage, bindingInfo, entry.ImageArray);
|
||||
}
|
||||
else
|
||||
{
|
||||
_context.Renderer.Pipeline.SetTextureArray(stage, bindingInfo.Binding, entry.TextureArray);
|
||||
SetTextureArray(stage, bindingInfo, entry.TextureArray);
|
||||
}
|
||||
|
||||
return;
|
||||
@@ -950,14 +950,50 @@ namespace Ryujinx.Graphics.Gpu.Image
|
||||
entry.ImageArray.SetFormats(0, formats);
|
||||
entry.ImageArray.SetImages(0, textures);
|
||||
|
||||
_context.Renderer.Pipeline.SetImageArray(stage, bindingInfo.Binding, entry.ImageArray);
|
||||
SetImageArray(stage, bindingInfo, entry.ImageArray);
|
||||
}
|
||||
else
|
||||
{
|
||||
entry.TextureArray.SetSamplers(0, samplers);
|
||||
entry.TextureArray.SetTextures(0, textures);
|
||||
|
||||
_context.Renderer.Pipeline.SetTextureArray(stage, bindingInfo.Binding, entry.TextureArray);
|
||||
SetTextureArray(stage, bindingInfo, entry.TextureArray);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Updates a texture array binding on the host.
|
||||
/// </summary>
|
||||
/// <param name="stage">Shader stage where the array is used</param>
|
||||
/// <param name="bindingInfo">Array binding information</param>
|
||||
/// <param name="array">Texture array</param>
|
||||
private void SetTextureArray(ShaderStage stage, in TextureBindingInfo bindingInfo, ITextureArray array)
|
||||
{
|
||||
if (bindingInfo.Set >= _context.Capabilities.ExtraSetBaseIndex && _context.Capabilities.MaximumExtraSets != 0)
|
||||
{
|
||||
_context.Renderer.Pipeline.SetTextureArraySeparate(stage, bindingInfo.Set, array);
|
||||
}
|
||||
else
|
||||
{
|
||||
_context.Renderer.Pipeline.SetTextureArray(stage, bindingInfo.Binding, array);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Updates a image array binding on the host.
|
||||
/// </summary>
|
||||
/// <param name="stage">Shader stage where the array is used</param>
|
||||
/// <param name="bindingInfo">Array binding information</param>
|
||||
/// <param name="array">Image array</param>
|
||||
private void SetImageArray(ShaderStage stage, in TextureBindingInfo bindingInfo, IImageArray array)
|
||||
{
|
||||
if (bindingInfo.Set >= _context.Capabilities.ExtraSetBaseIndex && _context.Capabilities.MaximumExtraSets != 0)
|
||||
{
|
||||
_context.Renderer.Pipeline.SetImageArraySeparate(stage, bindingInfo.Set, array);
|
||||
}
|
||||
else
|
||||
{
|
||||
_context.Renderer.Pipeline.SetImageArray(stage, bindingInfo.Binding, array);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -973,7 +1009,7 @@ namespace Ryujinx.Graphics.Gpu.Image
|
||||
private CacheEntry GetOrAddEntry(
|
||||
TexturePool texturePool,
|
||||
SamplerPool samplerPool,
|
||||
TextureBindingInfo bindingInfo,
|
||||
in TextureBindingInfo bindingInfo,
|
||||
bool isImage,
|
||||
out bool isNew)
|
||||
{
|
||||
@@ -1015,7 +1051,7 @@ namespace Ryujinx.Graphics.Gpu.Image
|
||||
private CacheEntryFromBuffer GetOrAddEntry(
|
||||
TexturePool texturePool,
|
||||
SamplerPool samplerPool,
|
||||
TextureBindingInfo bindingInfo,
|
||||
in TextureBindingInfo bindingInfo,
|
||||
bool isImage,
|
||||
ref BufferBounds textureBufferBounds,
|
||||
out bool isNew)
|
||||
|
@@ -62,6 +62,7 @@ namespace Ryujinx.Graphics.Gpu.Shader
|
||||
|
||||
var result = new TextureBindingInfo(
|
||||
target,
|
||||
descriptor.Set,
|
||||
descriptor.Binding,
|
||||
descriptor.ArrayLength,
|
||||
descriptor.CbufSlot,
|
||||
@@ -90,6 +91,7 @@ namespace Ryujinx.Graphics.Gpu.Shader
|
||||
var result = new TextureBindingInfo(
|
||||
target,
|
||||
format,
|
||||
descriptor.Set,
|
||||
descriptor.Binding,
|
||||
descriptor.ArrayLength,
|
||||
descriptor.CbufSlot,
|
||||
|
@@ -125,9 +125,18 @@ namespace Ryujinx.Graphics.Gpu.Shader.DiskCache
|
||||
CompressionAlgorithm algorithm = CompressionAlgorithm.None;
|
||||
Read(ref algorithm);
|
||||
|
||||
if (algorithm == CompressionAlgorithm.Deflate)
|
||||
switch (algorithm)
|
||||
{
|
||||
_activeStream = new DeflateStream(_stream, CompressionMode.Decompress, true);
|
||||
case CompressionAlgorithm.None:
|
||||
break;
|
||||
case CompressionAlgorithm.Deflate:
|
||||
_activeStream = new DeflateStream(_stream, CompressionMode.Decompress, true);
|
||||
break;
|
||||
case CompressionAlgorithm.Brotli:
|
||||
_activeStream = new BrotliStream(_stream, CompressionMode.Decompress, true);
|
||||
break;
|
||||
default:
|
||||
throw new ArgumentException($"Invalid compression algorithm \"{algorithm}\"");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -139,9 +148,18 @@ namespace Ryujinx.Graphics.Gpu.Shader.DiskCache
|
||||
{
|
||||
Write(ref algorithm);
|
||||
|
||||
if (algorithm == CompressionAlgorithm.Deflate)
|
||||
switch (algorithm)
|
||||
{
|
||||
_activeStream = new DeflateStream(_stream, CompressionLevel.Fastest, true);
|
||||
case CompressionAlgorithm.None:
|
||||
break;
|
||||
case CompressionAlgorithm.Deflate:
|
||||
_activeStream = new DeflateStream(_stream, CompressionLevel.Fastest, true);
|
||||
break;
|
||||
case CompressionAlgorithm.Brotli:
|
||||
_activeStream = new BrotliStream(_stream, CompressionLevel.Fastest, true);
|
||||
break;
|
||||
default:
|
||||
throw new ArgumentException($"Invalid compression algorithm \"{algorithm}\"");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -187,6 +205,14 @@ namespace Ryujinx.Graphics.Gpu.Shader.DiskCache
|
||||
}
|
||||
stream.Dispose();
|
||||
break;
|
||||
case CompressionAlgorithm.Brotli:
|
||||
stream = new BrotliStream(stream, CompressionMode.Decompress, true);
|
||||
for (int offset = 0; offset < data.Length;)
|
||||
{
|
||||
offset += stream.Read(data[offset..]);
|
||||
}
|
||||
stream.Dispose();
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -210,6 +236,11 @@ namespace Ryujinx.Graphics.Gpu.Shader.DiskCache
|
||||
stream.Write(data);
|
||||
stream.Dispose();
|
||||
break;
|
||||
case CompressionAlgorithm.Brotli:
|
||||
stream = new BrotliStream(stream, CompressionLevel.Fastest, true);
|
||||
stream.Write(data);
|
||||
stream.Dispose();
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@@ -14,5 +14,10 @@ namespace Ryujinx.Graphics.Gpu.Shader.DiskCache
|
||||
/// Deflate compression (RFC 1951).
|
||||
/// </summary>
|
||||
Deflate,
|
||||
|
||||
/// <summary>
|
||||
/// Brotli compression (RFC 7932).
|
||||
/// </summary>
|
||||
Brotli,
|
||||
}
|
||||
}
|
||||
|
@@ -51,7 +51,7 @@ namespace Ryujinx.Graphics.Gpu.Shader.DiskCache
|
||||
/// <returns>Compression algorithm</returns>
|
||||
public static CompressionAlgorithm GetCompressionAlgorithm()
|
||||
{
|
||||
return CompressionAlgorithm.Deflate;
|
||||
return CompressionAlgorithm.Brotli;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@@ -22,7 +22,7 @@ namespace Ryujinx.Graphics.Gpu.Shader.DiskCache
|
||||
private const ushort FileFormatVersionMajor = 1;
|
||||
private const ushort FileFormatVersionMinor = 2;
|
||||
private const uint FileFormatVersionPacked = ((uint)FileFormatVersionMajor << 16) | FileFormatVersionMinor;
|
||||
private const uint CodeGenVersion = 5936;
|
||||
private const uint CodeGenVersion = 6852;
|
||||
|
||||
private const string SharedTocFileName = "shared.toc";
|
||||
private const string SharedDataFileName = "shared.data";
|
||||
|
@@ -51,7 +51,7 @@ namespace Ryujinx.Graphics.Gpu.Shader
|
||||
_reservedImages = rrc.ReservedImages;
|
||||
}
|
||||
|
||||
public int CreateConstantBufferBinding(int index)
|
||||
public SetBindingPair CreateConstantBufferBinding(int index)
|
||||
{
|
||||
int binding;
|
||||
|
||||
@@ -64,10 +64,10 @@ namespace Ryujinx.Graphics.Gpu.Shader
|
||||
binding = _resourceCounts.UniformBuffersCount++;
|
||||
}
|
||||
|
||||
return binding + _reservedConstantBuffers;
|
||||
return new SetBindingPair(_context.Capabilities.UniformBufferSetIndex, binding + _reservedConstantBuffers);
|
||||
}
|
||||
|
||||
public int CreateImageBinding(int count, bool isBuffer)
|
||||
public SetBindingPair CreateImageBinding(int count, bool isBuffer)
|
||||
{
|
||||
int binding;
|
||||
|
||||
@@ -96,10 +96,10 @@ namespace Ryujinx.Graphics.Gpu.Shader
|
||||
_resourceCounts.ImagesCount += count;
|
||||
}
|
||||
|
||||
return binding + _reservedImages;
|
||||
return new SetBindingPair(_context.Capabilities.ImageSetIndex, binding + _reservedImages);
|
||||
}
|
||||
|
||||
public int CreateStorageBufferBinding(int index)
|
||||
public SetBindingPair CreateStorageBufferBinding(int index)
|
||||
{
|
||||
int binding;
|
||||
|
||||
@@ -112,10 +112,10 @@ namespace Ryujinx.Graphics.Gpu.Shader
|
||||
binding = _resourceCounts.StorageBuffersCount++;
|
||||
}
|
||||
|
||||
return binding + _reservedStorageBuffers;
|
||||
return new SetBindingPair(_context.Capabilities.StorageBufferSetIndex, binding + _reservedStorageBuffers);
|
||||
}
|
||||
|
||||
public int CreateTextureBinding(int count, bool isBuffer)
|
||||
public SetBindingPair CreateTextureBinding(int count, bool isBuffer)
|
||||
{
|
||||
int binding;
|
||||
|
||||
@@ -144,7 +144,7 @@ namespace Ryujinx.Graphics.Gpu.Shader
|
||||
_resourceCounts.TexturesCount += count;
|
||||
}
|
||||
|
||||
return binding + _reservedTextures;
|
||||
return new SetBindingPair(_context.Capabilities.TextureSetIndex, binding + _reservedTextures);
|
||||
}
|
||||
|
||||
private int GetBindingFromIndex(int index, uint maxPerStage, string resourceName)
|
||||
@@ -183,6 +183,16 @@ namespace Ryujinx.Graphics.Gpu.Shader
|
||||
return maxPerStage * Constants.ShaderStages;
|
||||
}
|
||||
|
||||
public int CreateExtraSet()
|
||||
{
|
||||
if (_resourceCounts.SetsCount >= _context.Capabilities.MaximumExtraSets)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
|
||||
return _context.Capabilities.ExtraSetBaseIndex + _resourceCounts.SetsCount++;
|
||||
}
|
||||
|
||||
public int QueryHostGatherBiasPrecision() => _context.Capabilities.GatherBiasPrecision;
|
||||
|
||||
public bool QueryHostReducedPrecision() => _context.Capabilities.ReduceShaderPrecision;
|
||||
|
@@ -24,5 +24,10 @@ namespace Ryujinx.Graphics.Gpu.Shader
|
||||
/// Total of images used by the shaders.
|
||||
/// </summary>
|
||||
public int ImagesCount;
|
||||
|
||||
/// <summary>
|
||||
/// Total of extra sets used by the shaders.
|
||||
/// </summary>
|
||||
public int SetsCount;
|
||||
}
|
||||
}
|
||||
|
@@ -1,5 +1,6 @@
|
||||
using Ryujinx.Graphics.GAL;
|
||||
using Ryujinx.Graphics.Shader;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace Ryujinx.Graphics.Gpu.Shader
|
||||
@@ -9,13 +10,6 @@ namespace Ryujinx.Graphics.Gpu.Shader
|
||||
/// </summary>
|
||||
class ShaderInfoBuilder
|
||||
{
|
||||
private const int TotalSets = 4;
|
||||
|
||||
private const int UniformSetIndex = 0;
|
||||
private const int StorageSetIndex = 1;
|
||||
private const int TextureSetIndex = 2;
|
||||
private const int ImageSetIndex = 3;
|
||||
|
||||
private const ResourceStages SupportBufferStages =
|
||||
ResourceStages.Compute |
|
||||
ResourceStages.Vertex |
|
||||
@@ -36,8 +30,8 @@ namespace Ryujinx.Graphics.Gpu.Shader
|
||||
private readonly int _reservedTextures;
|
||||
private readonly int _reservedImages;
|
||||
|
||||
private readonly List<ResourceDescriptor>[] _resourceDescriptors;
|
||||
private readonly List<ResourceUsage>[] _resourceUsages;
|
||||
private List<ResourceDescriptor>[] _resourceDescriptors;
|
||||
private List<ResourceUsage>[] _resourceUsages;
|
||||
|
||||
/// <summary>
|
||||
/// Creates a new shader info builder.
|
||||
@@ -51,17 +45,27 @@ namespace Ryujinx.Graphics.Gpu.Shader
|
||||
|
||||
_fragmentOutputMap = -1;
|
||||
|
||||
_resourceDescriptors = new List<ResourceDescriptor>[TotalSets];
|
||||
_resourceUsages = new List<ResourceUsage>[TotalSets];
|
||||
int uniformSetIndex = context.Capabilities.UniformBufferSetIndex;
|
||||
int storageSetIndex = context.Capabilities.StorageBufferSetIndex;
|
||||
int textureSetIndex = context.Capabilities.TextureSetIndex;
|
||||
int imageSetIndex = context.Capabilities.ImageSetIndex;
|
||||
|
||||
for (int index = 0; index < TotalSets; index++)
|
||||
int totalSets = Math.Max(uniformSetIndex, storageSetIndex);
|
||||
totalSets = Math.Max(totalSets, textureSetIndex);
|
||||
totalSets = Math.Max(totalSets, imageSetIndex);
|
||||
totalSets++;
|
||||
|
||||
_resourceDescriptors = new List<ResourceDescriptor>[totalSets];
|
||||
_resourceUsages = new List<ResourceUsage>[totalSets];
|
||||
|
||||
for (int index = 0; index < totalSets; index++)
|
||||
{
|
||||
_resourceDescriptors[index] = new();
|
||||
_resourceUsages[index] = new();
|
||||
}
|
||||
|
||||
AddDescriptor(SupportBufferStages, ResourceType.UniformBuffer, UniformSetIndex, 0, 1);
|
||||
AddUsage(SupportBufferStages, ResourceType.UniformBuffer, UniformSetIndex, 0, 1);
|
||||
AddDescriptor(SupportBufferStages, ResourceType.UniformBuffer, uniformSetIndex, 0, 1);
|
||||
AddUsage(SupportBufferStages, ResourceType.UniformBuffer, uniformSetIndex, 0, 1);
|
||||
|
||||
ResourceReservationCounts rrc = new(!context.Capabilities.SupportsTransformFeedback && tfEnabled, vertexAsCompute);
|
||||
|
||||
@@ -73,12 +77,20 @@ namespace Ryujinx.Graphics.Gpu.Shader
|
||||
// TODO: Handle that better? Maybe we should only set the binding that are really needed on each shader.
|
||||
ResourceStages stages = vertexAsCompute ? ResourceStages.Compute | ResourceStages.Vertex : VtgStages;
|
||||
|
||||
PopulateDescriptorAndUsages(stages, ResourceType.UniformBuffer, UniformSetIndex, 1, rrc.ReservedConstantBuffers - 1);
|
||||
PopulateDescriptorAndUsages(stages, ResourceType.StorageBuffer, StorageSetIndex, 0, rrc.ReservedStorageBuffers);
|
||||
PopulateDescriptorAndUsages(stages, ResourceType.BufferTexture, TextureSetIndex, 0, rrc.ReservedTextures);
|
||||
PopulateDescriptorAndUsages(stages, ResourceType.BufferImage, ImageSetIndex, 0, rrc.ReservedImages);
|
||||
PopulateDescriptorAndUsages(stages, ResourceType.UniformBuffer, uniformSetIndex, 1, rrc.ReservedConstantBuffers - 1);
|
||||
PopulateDescriptorAndUsages(stages, ResourceType.StorageBuffer, storageSetIndex, 0, rrc.ReservedStorageBuffers);
|
||||
PopulateDescriptorAndUsages(stages, ResourceType.BufferTexture, textureSetIndex, 0, rrc.ReservedTextures);
|
||||
PopulateDescriptorAndUsages(stages, ResourceType.BufferImage, imageSetIndex, 0, rrc.ReservedImages);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Populates descriptors and usages for vertex as compute and transform feedback emulation reserved resources.
|
||||
/// </summary>
|
||||
/// <param name="stages">Shader stages where the resources are used</param>
|
||||
/// <param name="type">Resource type</param>
|
||||
/// <param name="setIndex">Resource set index where the resources are used</param>
|
||||
/// <param name="start">First binding number</param>
|
||||
/// <param name="count">Amount of bindings</param>
|
||||
private void PopulateDescriptorAndUsages(ResourceStages stages, ResourceType type, int setIndex, int start, int count)
|
||||
{
|
||||
AddDescriptor(stages, type, setIndex, start, count);
|
||||
@@ -127,18 +139,23 @@ namespace Ryujinx.Graphics.Gpu.Shader
|
||||
int textureBinding = _reservedTextures + stageIndex * texturesPerStage * 2;
|
||||
int imageBinding = _reservedImages + stageIndex * imagesPerStage * 2;
|
||||
|
||||
AddDescriptor(stages, ResourceType.UniformBuffer, UniformSetIndex, uniformBinding, uniformsPerStage);
|
||||
AddDescriptor(stages, ResourceType.StorageBuffer, StorageSetIndex, storageBinding, storagesPerStage);
|
||||
AddDualDescriptor(stages, ResourceType.TextureAndSampler, ResourceType.BufferTexture, TextureSetIndex, textureBinding, texturesPerStage);
|
||||
AddDualDescriptor(stages, ResourceType.Image, ResourceType.BufferImage, ImageSetIndex, imageBinding, imagesPerStage);
|
||||
int uniformSetIndex = _context.Capabilities.UniformBufferSetIndex;
|
||||
int storageSetIndex = _context.Capabilities.StorageBufferSetIndex;
|
||||
int textureSetIndex = _context.Capabilities.TextureSetIndex;
|
||||
int imageSetIndex = _context.Capabilities.ImageSetIndex;
|
||||
|
||||
AddArrayDescriptors(info.Textures, stages, TextureSetIndex, isImage: false);
|
||||
AddArrayDescriptors(info.Images, stages, TextureSetIndex, isImage: true);
|
||||
AddDescriptor(stages, ResourceType.UniformBuffer, uniformSetIndex, uniformBinding, uniformsPerStage);
|
||||
AddDescriptor(stages, ResourceType.StorageBuffer, storageSetIndex, storageBinding, storagesPerStage);
|
||||
AddDualDescriptor(stages, ResourceType.TextureAndSampler, ResourceType.BufferTexture, textureSetIndex, textureBinding, texturesPerStage);
|
||||
AddDualDescriptor(stages, ResourceType.Image, ResourceType.BufferImage, imageSetIndex, imageBinding, imagesPerStage);
|
||||
|
||||
AddUsage(info.CBuffers, stages, UniformSetIndex, isStorage: false);
|
||||
AddUsage(info.SBuffers, stages, StorageSetIndex, isStorage: true);
|
||||
AddUsage(info.Textures, stages, TextureSetIndex, isImage: false);
|
||||
AddUsage(info.Images, stages, ImageSetIndex, isImage: true);
|
||||
AddArrayDescriptors(info.Textures, stages, isImage: false);
|
||||
AddArrayDescriptors(info.Images, stages, isImage: true);
|
||||
|
||||
AddUsage(info.CBuffers, stages, isStorage: false);
|
||||
AddUsage(info.SBuffers, stages, isStorage: true);
|
||||
AddUsage(info.Textures, stages, isImage: false);
|
||||
AddUsage(info.Images, stages, isImage: true);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -177,9 +194,8 @@ namespace Ryujinx.Graphics.Gpu.Shader
|
||||
/// </summary>
|
||||
/// <param name="textures">Textures to be added</param>
|
||||
/// <param name="stages">Stages where the textures are used</param>
|
||||
/// <param name="setIndex">Descriptor set index where the textures will be bound</param>
|
||||
/// <param name="isImage">True for images, false for textures</param>
|
||||
private void AddArrayDescriptors(IEnumerable<TextureDescriptor> textures, ResourceStages stages, int setIndex, bool isImage)
|
||||
private void AddArrayDescriptors(IEnumerable<TextureDescriptor> textures, ResourceStages stages, bool isImage)
|
||||
{
|
||||
foreach (TextureDescriptor texture in textures)
|
||||
{
|
||||
@@ -187,7 +203,7 @@ namespace Ryujinx.Graphics.Gpu.Shader
|
||||
{
|
||||
ResourceType type = GetTextureResourceType(texture, isImage);
|
||||
|
||||
_resourceDescriptors[setIndex].Add(new ResourceDescriptor(texture.Binding, texture.ArrayLength, type, stages));
|
||||
GetDescriptors(texture.Set).Add(new ResourceDescriptor(texture.Binding, texture.ArrayLength, type, stages));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -213,13 +229,12 @@ namespace Ryujinx.Graphics.Gpu.Shader
|
||||
/// </summary>
|
||||
/// <param name="buffers">Buffers to be added</param>
|
||||
/// <param name="stages">Stages where the buffers are used</param>
|
||||
/// <param name="setIndex">Descriptor set index where the buffers will be bound</param>
|
||||
/// <param name="isStorage">True for storage buffers, false for uniform buffers</param>
|
||||
private void AddUsage(IEnumerable<BufferDescriptor> buffers, ResourceStages stages, int setIndex, bool isStorage)
|
||||
private void AddUsage(IEnumerable<BufferDescriptor> buffers, ResourceStages stages, bool isStorage)
|
||||
{
|
||||
foreach (BufferDescriptor buffer in buffers)
|
||||
{
|
||||
_resourceUsages[setIndex].Add(new ResourceUsage(
|
||||
GetUsages(buffer.Set).Add(new ResourceUsage(
|
||||
buffer.Binding,
|
||||
1,
|
||||
isStorage ? ResourceType.StorageBuffer : ResourceType.UniformBuffer,
|
||||
@@ -232,18 +247,65 @@ namespace Ryujinx.Graphics.Gpu.Shader
|
||||
/// </summary>
|
||||
/// <param name="textures">Textures to be added</param>
|
||||
/// <param name="stages">Stages where the textures are used</param>
|
||||
/// <param name="setIndex">Descriptor set index where the textures will be bound</param>
|
||||
/// <param name="isImage">True for images, false for textures</param>
|
||||
private void AddUsage(IEnumerable<TextureDescriptor> textures, ResourceStages stages, int setIndex, bool isImage)
|
||||
private void AddUsage(IEnumerable<TextureDescriptor> textures, ResourceStages stages, bool isImage)
|
||||
{
|
||||
foreach (TextureDescriptor texture in textures)
|
||||
{
|
||||
ResourceType type = GetTextureResourceType(texture, isImage);
|
||||
|
||||
_resourceUsages[setIndex].Add(new ResourceUsage(texture.Binding, texture.ArrayLength, type, stages));
|
||||
GetUsages(texture.Set).Add(new ResourceUsage(texture.Binding, texture.ArrayLength, type, stages));
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the list of resource descriptors for a given set index. A new list will be created if needed.
|
||||
/// </summary>
|
||||
/// <param name="setIndex">Resource set index</param>
|
||||
/// <returns>List of resource descriptors</returns>
|
||||
private List<ResourceDescriptor> GetDescriptors(int setIndex)
|
||||
{
|
||||
if (_resourceDescriptors.Length <= setIndex)
|
||||
{
|
||||
int oldLength = _resourceDescriptors.Length;
|
||||
Array.Resize(ref _resourceDescriptors, setIndex + 1);
|
||||
|
||||
for (int index = oldLength; index <= setIndex; index++)
|
||||
{
|
||||
_resourceDescriptors[index] = new();
|
||||
}
|
||||
}
|
||||
|
||||
return _resourceDescriptors[setIndex];
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the list of resource usages for a given set index. A new list will be created if needed.
|
||||
/// </summary>
|
||||
/// <param name="setIndex">Resource set index</param>
|
||||
/// <returns>List of resource usages</returns>
|
||||
private List<ResourceUsage> GetUsages(int setIndex)
|
||||
{
|
||||
if (_resourceUsages.Length <= setIndex)
|
||||
{
|
||||
int oldLength = _resourceUsages.Length;
|
||||
Array.Resize(ref _resourceUsages, setIndex + 1);
|
||||
|
||||
for (int index = oldLength; index <= setIndex; index++)
|
||||
{
|
||||
_resourceUsages[index] = new();
|
||||
}
|
||||
}
|
||||
|
||||
return _resourceUsages[setIndex];
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets a resource type from a texture descriptor.
|
||||
/// </summary>
|
||||
/// <param name="texture">Texture descriptor</param>
|
||||
/// <param name="isImage">Whether the texture is a image texture (writable) or not (sampled)</param>
|
||||
/// <returns>Resource type</returns>
|
||||
private static ResourceType GetTextureResourceType(TextureDescriptor texture, bool isImage)
|
||||
{
|
||||
bool isBuffer = (texture.Type & SamplerType.Mask) == SamplerType.TextureBuffer;
|
||||
@@ -278,10 +340,12 @@ namespace Ryujinx.Graphics.Gpu.Shader
|
||||
/// <returns>Shader information</returns>
|
||||
public ShaderInfo Build(ProgramPipelineState? pipeline, bool fromCache = false)
|
||||
{
|
||||
var descriptors = new ResourceDescriptorCollection[TotalSets];
|
||||
var usages = new ResourceUsageCollection[TotalSets];
|
||||
int totalSets = _resourceDescriptors.Length;
|
||||
|
||||
for (int index = 0; index < TotalSets; index++)
|
||||
var descriptors = new ResourceDescriptorCollection[totalSets];
|
||||
var usages = new ResourceUsageCollection[totalSets];
|
||||
|
||||
for (int index = 0; index < totalSets; index++)
|
||||
{
|
||||
descriptors[index] = new ResourceDescriptorCollection(_resourceDescriptors[index].ToArray().AsReadOnly());
|
||||
usages[index] = new ResourceUsageCollection(_resourceUsages[index].ToArray().AsReadOnly());
|
||||
|
@@ -187,6 +187,12 @@ namespace Ryujinx.Graphics.OpenGL
|
||||
supportsViewportSwizzle: HwCapabilities.SupportsViewportSwizzle,
|
||||
supportsIndirectParameters: HwCapabilities.SupportsIndirectParameters,
|
||||
supportsDepthClipControl: true,
|
||||
uniformBufferSetIndex: 0,
|
||||
storageBufferSetIndex: 1,
|
||||
textureSetIndex: 2,
|
||||
imageSetIndex: 3,
|
||||
extraSetBaseIndex: 0,
|
||||
maximumExtraSets: 0,
|
||||
maximumUniformBuffersPerStage: 13, // TODO: Avoid hardcoding those limits here and get from driver?
|
||||
maximumStorageBuffersPerStage: 16,
|
||||
maximumTexturesPerStage: 32,
|
||||
|
@@ -963,6 +963,11 @@ namespace Ryujinx.Graphics.OpenGL
|
||||
(array as ImageArray).Bind(binding);
|
||||
}
|
||||
|
||||
public void SetImageArraySeparate(ShaderStage stage, int setIndex, IImageArray array)
|
||||
{
|
||||
throw new NotSupportedException("OpenGL does not support descriptor sets.");
|
||||
}
|
||||
|
||||
public void SetIndexBuffer(BufferRange buffer, IndexType type)
|
||||
{
|
||||
_elementsType = type.Convert();
|
||||
@@ -1312,6 +1317,11 @@ namespace Ryujinx.Graphics.OpenGL
|
||||
(array as TextureArray).Bind(binding);
|
||||
}
|
||||
|
||||
public void SetTextureArraySeparate(ShaderStage stage, int setIndex, ITextureArray array)
|
||||
{
|
||||
throw new NotSupportedException("OpenGL does not support descriptor sets.");
|
||||
}
|
||||
|
||||
public void SetTransformFeedbackBuffers(ReadOnlySpan<BufferRange> buffers)
|
||||
{
|
||||
if (_tfEnabled)
|
||||
|
@@ -4,14 +4,16 @@ namespace Ryujinx.Graphics.Shader
|
||||
{
|
||||
// New fields should be added to the end of the struct to keep disk shader cache compatibility.
|
||||
|
||||
public readonly int Set;
|
||||
public readonly int Binding;
|
||||
public readonly byte Slot;
|
||||
public readonly byte SbCbSlot;
|
||||
public readonly ushort SbCbOffset;
|
||||
public readonly BufferUsageFlags Flags;
|
||||
|
||||
public BufferDescriptor(int binding, int slot)
|
||||
public BufferDescriptor(int set, int binding, int slot)
|
||||
{
|
||||
Set = set;
|
||||
Binding = binding;
|
||||
Slot = (byte)slot;
|
||||
SbCbSlot = 0;
|
||||
@@ -19,8 +21,9 @@ namespace Ryujinx.Graphics.Shader
|
||||
Flags = BufferUsageFlags.None;
|
||||
}
|
||||
|
||||
public BufferDescriptor(int binding, int slot, int sbCbSlot, int sbCbOffset, BufferUsageFlags flags)
|
||||
public BufferDescriptor(int set, int binding, int slot, int sbCbSlot, int sbCbOffset, BufferUsageFlags flags)
|
||||
{
|
||||
Set = set;
|
||||
Binding = binding;
|
||||
Slot = (byte)slot;
|
||||
SbCbSlot = (byte)sbCbSlot;
|
||||
|
@@ -462,7 +462,7 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Glsl.Instructions
|
||||
}
|
||||
else
|
||||
{
|
||||
context.Properties.Textures.TryGetValue(texOp.Binding, out TextureDefinition definition);
|
||||
context.Properties.Textures.TryGetValue(texOp.GetTextureSetAndBinding(), out TextureDefinition definition);
|
||||
bool hasLod = !definition.Type.HasFlag(SamplerType.Multisample) && (definition.Type & SamplerType.Mask) != SamplerType.TextureBuffer;
|
||||
string texCall;
|
||||
|
||||
@@ -639,7 +639,7 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Glsl.Instructions
|
||||
|
||||
private static string GetSamplerName(CodeGenContext context, AstTextureOperation texOp, ref int srcIndex)
|
||||
{
|
||||
TextureDefinition textureDefinition = context.Properties.Textures[texOp.Binding];
|
||||
TextureDefinition textureDefinition = context.Properties.Textures[texOp.GetTextureSetAndBinding()];
|
||||
string name = textureDefinition.Name;
|
||||
|
||||
if (textureDefinition.ArrayLength != 1)
|
||||
@@ -649,7 +649,7 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Glsl.Instructions
|
||||
|
||||
if (texOp.IsSeparate)
|
||||
{
|
||||
TextureDefinition samplerDefinition = context.Properties.Textures[texOp.SamplerBinding];
|
||||
TextureDefinition samplerDefinition = context.Properties.Textures[texOp.GetSamplerSetAndBinding()];
|
||||
string samplerName = samplerDefinition.Name;
|
||||
|
||||
if (samplerDefinition.ArrayLength != 1)
|
||||
@@ -665,7 +665,7 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Glsl.Instructions
|
||||
|
||||
private static string GetImageName(CodeGenContext context, AstTextureOperation texOp, ref int srcIndex)
|
||||
{
|
||||
TextureDefinition definition = context.Properties.Images[texOp.Binding];
|
||||
TextureDefinition definition = context.Properties.Images[texOp.GetTextureSetAndBinding()];
|
||||
string name = definition.Name;
|
||||
|
||||
if (definition.ArrayLength != 1)
|
||||
|
@@ -33,9 +33,9 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Spirv
|
||||
public Dictionary<int, Instruction> LocalMemories { get; } = new();
|
||||
public Dictionary<int, Instruction> SharedMemories { get; } = new();
|
||||
|
||||
public Dictionary<int, SamplerType> SamplersTypes { get; } = new();
|
||||
public Dictionary<int, SamplerDeclaration> Samplers { get; } = new();
|
||||
public Dictionary<int, ImageDeclaration> Images { get; } = new();
|
||||
public Dictionary<SetBindingPair, SamplerType> SamplersTypes { get; } = new();
|
||||
public Dictionary<SetBindingPair, SamplerDeclaration> Samplers { get; } = new();
|
||||
public Dictionary<SetBindingPair, ImageDeclaration> Images { get; } = new();
|
||||
|
||||
public Dictionary<IoDefinition, Instruction> Inputs { get; } = new();
|
||||
public Dictionary<IoDefinition, Instruction> Outputs { get; } = new();
|
||||
|
@@ -208,13 +208,13 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Spirv
|
||||
|
||||
var sampledImageVariable = context.Variable(sampledImageArrayPointerType, StorageClass.UniformConstant);
|
||||
|
||||
context.Samplers.Add(sampler.Binding, new SamplerDeclaration(
|
||||
context.Samplers.Add(new(sampler.Set, sampler.Binding), new SamplerDeclaration(
|
||||
imageType,
|
||||
sampledImageType,
|
||||
sampledImagePointerType,
|
||||
sampledImageVariable,
|
||||
sampler.ArrayLength != 1));
|
||||
context.SamplersTypes.Add(sampler.Binding, sampler.Type);
|
||||
context.SamplersTypes.Add(new(sampler.Set, sampler.Binding), sampler.Type);
|
||||
|
||||
context.Name(sampledImageVariable, sampler.Name);
|
||||
context.Decorate(sampledImageVariable, Decoration.DescriptorSet, (LiteralInteger)setIndex);
|
||||
@@ -256,7 +256,7 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Spirv
|
||||
|
||||
var imageVariable = context.Variable(imageArrayPointerType, StorageClass.UniformConstant);
|
||||
|
||||
context.Images.Add(image.Binding, new ImageDeclaration(imageType, imagePointerType, imageVariable, image.ArrayLength != 1));
|
||||
context.Images.Add(new(image.Set, image.Binding), new ImageDeclaration(imageType, imagePointerType, imageVariable, image.ArrayLength != 1));
|
||||
|
||||
context.Name(imageVariable, image.Name);
|
||||
context.Decorate(imageVariable, Decoration.DescriptorSet, (LiteralInteger)setIndex);
|
||||
|
@@ -602,7 +602,7 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Spirv
|
||||
return context.Get(type, texOp.GetSource(srcIndex++));
|
||||
}
|
||||
|
||||
ImageDeclaration declaration = context.Images[texOp.Binding];
|
||||
ImageDeclaration declaration = context.Images[texOp.GetTextureSetAndBinding()];
|
||||
SpvInstruction image = declaration.Image;
|
||||
|
||||
SpvInstruction resultType = context.GetType(componentType);
|
||||
@@ -681,7 +681,7 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Spirv
|
||||
return context.Get(type, texOp.GetSource(srcIndex++));
|
||||
}
|
||||
|
||||
ImageDeclaration declaration = context.Images[texOp.Binding];
|
||||
ImageDeclaration declaration = context.Images[texOp.GetTextureSetAndBinding()];
|
||||
SpvInstruction image = declaration.Image;
|
||||
|
||||
if (declaration.IsIndexed)
|
||||
@@ -738,7 +738,7 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Spirv
|
||||
return context.Get(type, texOp.GetSource(srcIndex++));
|
||||
}
|
||||
|
||||
ImageDeclaration declaration = context.Images[texOp.Binding];
|
||||
ImageDeclaration declaration = context.Images[texOp.GetTextureSetAndBinding()];
|
||||
SpvInstruction image = declaration.Image;
|
||||
|
||||
if (declaration.IsIndexed)
|
||||
@@ -837,7 +837,7 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Spirv
|
||||
return context.Get(type, texOp.GetSource(srcIndex++));
|
||||
}
|
||||
|
||||
SamplerDeclaration declaration = context.Samplers[texOp.Binding];
|
||||
SamplerDeclaration declaration = context.Samplers[texOp.GetTextureSetAndBinding()];
|
||||
SpvInstruction image = GenerateSampledImageLoad(context, texOp, declaration, ref srcIndex);
|
||||
|
||||
int pCount = texOp.Type.GetDimensions();
|
||||
@@ -1161,7 +1161,7 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Spirv
|
||||
return context.Get(type, texOp.GetSource(srcIndex++));
|
||||
}
|
||||
|
||||
SamplerDeclaration declaration = context.Samplers[texOp.Binding];
|
||||
SamplerDeclaration declaration = context.Samplers[texOp.GetTextureSetAndBinding()];
|
||||
SpvInstruction image = GenerateSampledImageLoad(context, texOp, declaration, ref srcIndex);
|
||||
|
||||
int coordsCount = texOp.Type.GetDimensions();
|
||||
@@ -1433,7 +1433,7 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Spirv
|
||||
|
||||
int srcIndex = 0;
|
||||
|
||||
SamplerDeclaration declaration = context.Samplers[texOp.Binding];
|
||||
SamplerDeclaration declaration = context.Samplers[texOp.GetTextureSetAndBinding()];
|
||||
SpvInstruction image = GenerateSampledImageLoad(context, texOp, declaration, ref srcIndex);
|
||||
|
||||
image = context.Image(declaration.ImageType, image);
|
||||
@@ -1449,7 +1449,7 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Spirv
|
||||
|
||||
int srcIndex = 0;
|
||||
|
||||
SamplerDeclaration declaration = context.Samplers[texOp.Binding];
|
||||
SamplerDeclaration declaration = context.Samplers[texOp.GetTextureSetAndBinding()];
|
||||
SpvInstruction image = GenerateSampledImageLoad(context, texOp, declaration, ref srcIndex);
|
||||
|
||||
image = context.Image(declaration.ImageType, image);
|
||||
@@ -1460,7 +1460,7 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Spirv
|
||||
}
|
||||
else
|
||||
{
|
||||
var type = context.SamplersTypes[texOp.Binding];
|
||||
var type = context.SamplersTypes[texOp.GetTextureSetAndBinding()];
|
||||
bool hasLod = !type.HasFlag(SamplerType.Multisample) && type != SamplerType.TextureBuffer;
|
||||
|
||||
int dimensions = (type & SamplerType.Mask) == SamplerType.TextureCube ? 2 : type.GetDimensions();
|
||||
@@ -1889,7 +1889,7 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Spirv
|
||||
{
|
||||
image = context.Load(declaration.ImageType, image);
|
||||
|
||||
SamplerDeclaration samplerDeclaration = context.Samplers[texOp.SamplerBinding];
|
||||
SamplerDeclaration samplerDeclaration = context.Samplers[texOp.GetSamplerSetAndBinding()];
|
||||
|
||||
SpvInstruction sampler = samplerDeclaration.Image;
|
||||
|
||||
|
@@ -27,34 +27,43 @@ namespace Ryujinx.Graphics.Shader
|
||||
ReadOnlySpan<ulong> GetCode(ulong address, int minimumSize);
|
||||
|
||||
/// <summary>
|
||||
/// Queries the binding number of a constant buffer.
|
||||
/// Gets the binding number of a constant buffer.
|
||||
/// </summary>
|
||||
/// <param name="index">Constant buffer index</param>
|
||||
/// <returns>Binding number</returns>
|
||||
int CreateConstantBufferBinding(int index);
|
||||
SetBindingPair CreateConstantBufferBinding(int index);
|
||||
|
||||
/// <summary>
|
||||
/// Queries the binding number of an image.
|
||||
/// Gets the binding number of an image.
|
||||
/// </summary>
|
||||
/// <param name="count">For array of images, the number of elements of the array, otherwise it should be 1</param>
|
||||
/// <param name="isBuffer">Indicates if the image is a buffer image</param>
|
||||
/// <returns>Binding number</returns>
|
||||
int CreateImageBinding(int count, bool isBuffer);
|
||||
SetBindingPair CreateImageBinding(int count, bool isBuffer);
|
||||
|
||||
/// <summary>
|
||||
/// Queries the binding number of a storage buffer.
|
||||
/// Gets the binding number of a storage buffer.
|
||||
/// </summary>
|
||||
/// <param name="index">Storage buffer index</param>
|
||||
/// <returns>Binding number</returns>
|
||||
int CreateStorageBufferBinding(int index);
|
||||
SetBindingPair CreateStorageBufferBinding(int index);
|
||||
|
||||
/// <summary>
|
||||
/// Queries the binding number of a texture.
|
||||
/// Gets the binding number of a texture.
|
||||
/// </summary>
|
||||
/// <param name="count">For array of textures, the number of elements of the array, otherwise it should be 1</param>
|
||||
/// <param name="isBuffer">Indicates if the texture is a buffer texture</param>
|
||||
/// <returns>Binding number</returns>
|
||||
int CreateTextureBinding(int count, bool isBuffer);
|
||||
SetBindingPair CreateTextureBinding(int count, bool isBuffer);
|
||||
|
||||
/// <summary>
|
||||
/// Gets the set index for an additional set, or -1 if there's no extra set available.
|
||||
/// </summary>
|
||||
/// <returns>Extra set index, or -1 if not available</returns>
|
||||
int CreateExtraSet()
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Queries Local Size X for compute shaders.
|
||||
|
@@ -278,7 +278,7 @@ namespace Ryujinx.Graphics.Shader.Instructions
|
||||
flags |= TextureFlags.Bindless;
|
||||
}
|
||||
|
||||
int binding = isBindless ? 0 : context.ResourceManager.GetTextureOrImageBinding(
|
||||
SetBindingPair setAndBinding = isBindless ? default : context.ResourceManager.GetTextureOrImageBinding(
|
||||
Instruction.ImageAtomic,
|
||||
type,
|
||||
format,
|
||||
@@ -286,7 +286,7 @@ namespace Ryujinx.Graphics.Shader.Instructions
|
||||
TextureOperation.DefaultCbufSlot,
|
||||
imm);
|
||||
|
||||
Operand res = context.ImageAtomic(type, format, flags, binding, sources);
|
||||
Operand res = context.ImageAtomic(type, format, flags, setAndBinding, sources);
|
||||
|
||||
context.Copy(d, res);
|
||||
}
|
||||
@@ -389,7 +389,7 @@ namespace Ryujinx.Graphics.Shader.Instructions
|
||||
|
||||
TextureFormat format = isBindless ? TextureFormat.Unknown : ShaderProperties.GetTextureFormat(context.TranslatorContext.GpuAccessor, handle);
|
||||
|
||||
int binding = isBindless ? 0 : context.ResourceManager.GetTextureOrImageBinding(
|
||||
SetBindingPair setAndBinding = isBindless ? default : context.ResourceManager.GetTextureOrImageBinding(
|
||||
Instruction.ImageLoad,
|
||||
type,
|
||||
format,
|
||||
@@ -397,7 +397,7 @@ namespace Ryujinx.Graphics.Shader.Instructions
|
||||
TextureOperation.DefaultCbufSlot,
|
||||
handle);
|
||||
|
||||
context.ImageLoad(type, format, flags, binding, (int)componentMask, dests, sources);
|
||||
context.ImageLoad(type, format, flags, setAndBinding, (int)componentMask, dests, sources);
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -432,7 +432,7 @@ namespace Ryujinx.Graphics.Shader.Instructions
|
||||
|
||||
TextureFormat format = GetTextureFormat(size);
|
||||
|
||||
int binding = isBindless ? 0 : context.ResourceManager.GetTextureOrImageBinding(
|
||||
SetBindingPair setAndBinding = isBindless ? default : context.ResourceManager.GetTextureOrImageBinding(
|
||||
Instruction.ImageLoad,
|
||||
type,
|
||||
format,
|
||||
@@ -440,7 +440,7 @@ namespace Ryujinx.Graphics.Shader.Instructions
|
||||
TextureOperation.DefaultCbufSlot,
|
||||
handle);
|
||||
|
||||
context.ImageLoad(type, format, flags, binding, compMask, dests, sources);
|
||||
context.ImageLoad(type, format, flags, setAndBinding, compMask, dests, sources);
|
||||
|
||||
switch (size)
|
||||
{
|
||||
@@ -552,7 +552,7 @@ namespace Ryujinx.Graphics.Shader.Instructions
|
||||
flags |= TextureFlags.Bindless;
|
||||
}
|
||||
|
||||
int binding = isBindless ? 0 : context.ResourceManager.GetTextureOrImageBinding(
|
||||
SetBindingPair setAndBinding = isBindless ? default : context.ResourceManager.GetTextureOrImageBinding(
|
||||
Instruction.ImageAtomic,
|
||||
type,
|
||||
format,
|
||||
@@ -560,7 +560,7 @@ namespace Ryujinx.Graphics.Shader.Instructions
|
||||
TextureOperation.DefaultCbufSlot,
|
||||
imm);
|
||||
|
||||
context.ImageAtomic(type, format, flags, binding, sources);
|
||||
context.ImageAtomic(type, format, flags, setAndBinding, sources);
|
||||
}
|
||||
|
||||
private static void EmitSust(
|
||||
@@ -679,7 +679,7 @@ namespace Ryujinx.Graphics.Shader.Instructions
|
||||
flags |= TextureFlags.Coherent;
|
||||
}
|
||||
|
||||
int binding = isBindless ? 0 : context.ResourceManager.GetTextureOrImageBinding(
|
||||
SetBindingPair setAndBinding = isBindless ? default : context.ResourceManager.GetTextureOrImageBinding(
|
||||
Instruction.ImageStore,
|
||||
type,
|
||||
format,
|
||||
@@ -687,7 +687,7 @@ namespace Ryujinx.Graphics.Shader.Instructions
|
||||
TextureOperation.DefaultCbufSlot,
|
||||
handle);
|
||||
|
||||
context.ImageStore(type, format, flags, binding, sources);
|
||||
context.ImageStore(type, format, flags, setAndBinding, sources);
|
||||
}
|
||||
|
||||
private static int GetComponentSizeInBytesLog2(SuatomSize size)
|
||||
|
@@ -885,7 +885,7 @@ namespace Ryujinx.Graphics.Shader.Instructions
|
||||
return Register(dest++, RegisterType.Gpr);
|
||||
}
|
||||
|
||||
int binding = isBindless ? 0 : context.ResourceManager.GetTextureOrImageBinding(
|
||||
SetBindingPair setAndBinding = isBindless ? default : context.ResourceManager.GetTextureOrImageBinding(
|
||||
Instruction.Lod,
|
||||
type,
|
||||
TextureFormat.Unknown,
|
||||
@@ -913,7 +913,7 @@ namespace Ryujinx.Graphics.Shader.Instructions
|
||||
else
|
||||
{
|
||||
// The instruction component order is the inverse of GLSL's.
|
||||
Operand res = context.Lod(type, flags, binding, compIndex ^ 1, sources);
|
||||
Operand res = context.Lod(type, flags, setAndBinding, compIndex ^ 1, sources);
|
||||
|
||||
res = context.FPMultiply(res, ConstF(256.0f));
|
||||
|
||||
@@ -1116,12 +1116,12 @@ namespace Ryujinx.Graphics.Shader.Instructions
|
||||
}
|
||||
|
||||
TextureFlags flags = isBindless ? TextureFlags.Bindless : TextureFlags.None;
|
||||
int binding;
|
||||
SetBindingPair setAndBinding;
|
||||
|
||||
switch (query)
|
||||
{
|
||||
case TexQuery.TexHeaderDimension:
|
||||
binding = isBindless ? 0 : context.ResourceManager.GetTextureOrImageBinding(
|
||||
setAndBinding = isBindless ? default : context.ResourceManager.GetTextureOrImageBinding(
|
||||
Instruction.TextureQuerySize,
|
||||
type,
|
||||
TextureFormat.Unknown,
|
||||
@@ -1140,13 +1140,13 @@ namespace Ryujinx.Graphics.Shader.Instructions
|
||||
break;
|
||||
}
|
||||
|
||||
context.Copy(d, context.TextureQuerySize(type, flags, binding, compIndex, sources));
|
||||
context.Copy(d, context.TextureQuerySize(type, flags, setAndBinding, compIndex, sources));
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case TexQuery.TexHeaderTextureType:
|
||||
binding = isBindless ? 0 : context.ResourceManager.GetTextureOrImageBinding(
|
||||
setAndBinding = isBindless ? default : context.ResourceManager.GetTextureOrImageBinding(
|
||||
Instruction.TextureQuerySamples,
|
||||
type,
|
||||
TextureFormat.Unknown,
|
||||
@@ -1171,7 +1171,7 @@ namespace Ryujinx.Graphics.Shader.Instructions
|
||||
|
||||
if (d != null)
|
||||
{
|
||||
context.Copy(d, context.TextureQuerySamples(type, flags, binding, sources));
|
||||
context.Copy(d, context.TextureQuerySamples(type, flags, setAndBinding, sources));
|
||||
}
|
||||
}
|
||||
break;
|
||||
@@ -1191,7 +1191,7 @@ namespace Ryujinx.Graphics.Shader.Instructions
|
||||
Operand[] dests,
|
||||
Operand[] sources)
|
||||
{
|
||||
int binding = flags.HasFlag(TextureFlags.Bindless) ? 0 : context.ResourceManager.GetTextureOrImageBinding(
|
||||
SetBindingPair setAndBinding = flags.HasFlag(TextureFlags.Bindless) ? default : context.ResourceManager.GetTextureOrImageBinding(
|
||||
Instruction.TextureSample,
|
||||
type,
|
||||
TextureFormat.Unknown,
|
||||
@@ -1199,7 +1199,7 @@ namespace Ryujinx.Graphics.Shader.Instructions
|
||||
TextureOperation.DefaultCbufSlot,
|
||||
handle);
|
||||
|
||||
context.TextureSample(type, flags, binding, componentMask, dests, sources);
|
||||
context.TextureSample(type, flags, setAndBinding, componentMask, dests, sources);
|
||||
}
|
||||
|
||||
private static SamplerType ConvertSamplerType(TexDim dimensions)
|
||||
|
@@ -8,7 +8,9 @@ namespace Ryujinx.Graphics.Shader.IntermediateRepresentation
|
||||
public TextureFormat Format { get; set; }
|
||||
public TextureFlags Flags { get; private set; }
|
||||
|
||||
public int Set { get; private set; }
|
||||
public int Binding { get; private set; }
|
||||
public int SamplerSet { get; private set; }
|
||||
public int SamplerBinding { get; private set; }
|
||||
|
||||
public TextureOperation(
|
||||
@@ -16,6 +18,7 @@ namespace Ryujinx.Graphics.Shader.IntermediateRepresentation
|
||||
SamplerType type,
|
||||
TextureFormat format,
|
||||
TextureFlags flags,
|
||||
int set,
|
||||
int binding,
|
||||
int compIndex,
|
||||
Operand[] dests,
|
||||
@@ -24,24 +27,28 @@ namespace Ryujinx.Graphics.Shader.IntermediateRepresentation
|
||||
Type = type;
|
||||
Format = format;
|
||||
Flags = flags;
|
||||
Set = set;
|
||||
Binding = binding;
|
||||
SamplerSet = -1;
|
||||
SamplerBinding = -1;
|
||||
}
|
||||
|
||||
public void TurnIntoArray(int binding)
|
||||
public void TurnIntoArray(SetBindingPair setAndBinding)
|
||||
{
|
||||
Flags &= ~TextureFlags.Bindless;
|
||||
Binding = binding;
|
||||
Set = setAndBinding.SetIndex;
|
||||
Binding = setAndBinding.Binding;
|
||||
}
|
||||
|
||||
public void TurnIntoArray(int textureBinding, int samplerBinding)
|
||||
public void TurnIntoArray(SetBindingPair textureSetAndBinding, SetBindingPair samplerSetAndBinding)
|
||||
{
|
||||
TurnIntoArray(textureBinding);
|
||||
TurnIntoArray(textureSetAndBinding);
|
||||
|
||||
SamplerBinding = samplerBinding;
|
||||
SamplerSet = samplerSetAndBinding.SetIndex;
|
||||
SamplerBinding = samplerSetAndBinding.Binding;
|
||||
}
|
||||
|
||||
public void SetBinding(int binding)
|
||||
public void SetBinding(SetBindingPair setAndBinding)
|
||||
{
|
||||
if ((Flags & TextureFlags.Bindless) != 0)
|
||||
{
|
||||
@@ -50,7 +57,8 @@ namespace Ryujinx.Graphics.Shader.IntermediateRepresentation
|
||||
RemoveSource(0);
|
||||
}
|
||||
|
||||
Binding = binding;
|
||||
Set = setAndBinding.SetIndex;
|
||||
Binding = setAndBinding.Binding;
|
||||
}
|
||||
|
||||
public void SetLodLevelFlag()
|
||||
|
4
ryujinx/src/Ryujinx.Graphics.Shader/SetBindingPair.cs
Normal file
4
ryujinx/src/Ryujinx.Graphics.Shader/SetBindingPair.cs
Normal file
@@ -0,0 +1,4 @@
|
||||
namespace Ryujinx.Graphics.Shader
|
||||
{
|
||||
public readonly record struct SetBindingPair(int SetIndex, int Binding);
|
||||
}
|
@@ -8,7 +8,9 @@ namespace Ryujinx.Graphics.Shader.StructuredIr
|
||||
public TextureFormat Format { get; }
|
||||
public TextureFlags Flags { get; }
|
||||
|
||||
public int Set { get; }
|
||||
public int Binding { get; }
|
||||
public int SamplerSet { get; }
|
||||
public int SamplerBinding { get; }
|
||||
|
||||
public bool IsSeparate => SamplerBinding >= 0;
|
||||
@@ -18,7 +20,9 @@ namespace Ryujinx.Graphics.Shader.StructuredIr
|
||||
SamplerType type,
|
||||
TextureFormat format,
|
||||
TextureFlags flags,
|
||||
int set,
|
||||
int binding,
|
||||
int samplerSet,
|
||||
int samplerBinding,
|
||||
int index,
|
||||
params IAstNode[] sources) : base(inst, StorageKind.None, false, index, sources, sources.Length)
|
||||
@@ -26,8 +30,20 @@ namespace Ryujinx.Graphics.Shader.StructuredIr
|
||||
Type = type;
|
||||
Format = format;
|
||||
Flags = flags;
|
||||
Set = set;
|
||||
Binding = binding;
|
||||
SamplerSet = samplerSet;
|
||||
SamplerBinding = samplerBinding;
|
||||
}
|
||||
|
||||
public SetBindingPair GetTextureSetAndBinding()
|
||||
{
|
||||
return new SetBindingPair(Set, Binding);
|
||||
}
|
||||
|
||||
public SetBindingPair GetSamplerSetAndBinding()
|
||||
{
|
||||
return new SetBindingPair(SamplerSet, SamplerBinding);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@@ -6,15 +6,15 @@ namespace Ryujinx.Graphics.Shader.StructuredIr
|
||||
{
|
||||
private readonly Dictionary<int, BufferDefinition> _constantBuffers;
|
||||
private readonly Dictionary<int, BufferDefinition> _storageBuffers;
|
||||
private readonly Dictionary<int, TextureDefinition> _textures;
|
||||
private readonly Dictionary<int, TextureDefinition> _images;
|
||||
private readonly Dictionary<SetBindingPair, TextureDefinition> _textures;
|
||||
private readonly Dictionary<SetBindingPair, TextureDefinition> _images;
|
||||
private readonly Dictionary<int, MemoryDefinition> _localMemories;
|
||||
private readonly Dictionary<int, MemoryDefinition> _sharedMemories;
|
||||
|
||||
public IReadOnlyDictionary<int, BufferDefinition> ConstantBuffers => _constantBuffers;
|
||||
public IReadOnlyDictionary<int, BufferDefinition> StorageBuffers => _storageBuffers;
|
||||
public IReadOnlyDictionary<int, TextureDefinition> Textures => _textures;
|
||||
public IReadOnlyDictionary<int, TextureDefinition> Images => _images;
|
||||
public IReadOnlyDictionary<SetBindingPair, TextureDefinition> Textures => _textures;
|
||||
public IReadOnlyDictionary<SetBindingPair, TextureDefinition> Images => _images;
|
||||
public IReadOnlyDictionary<int, MemoryDefinition> LocalMemories => _localMemories;
|
||||
public IReadOnlyDictionary<int, MemoryDefinition> SharedMemories => _sharedMemories;
|
||||
|
||||
@@ -22,8 +22,8 @@ namespace Ryujinx.Graphics.Shader.StructuredIr
|
||||
{
|
||||
_constantBuffers = new Dictionary<int, BufferDefinition>();
|
||||
_storageBuffers = new Dictionary<int, BufferDefinition>();
|
||||
_textures = new Dictionary<int, TextureDefinition>();
|
||||
_images = new Dictionary<int, TextureDefinition>();
|
||||
_textures = new Dictionary<SetBindingPair, TextureDefinition>();
|
||||
_images = new Dictionary<SetBindingPair, TextureDefinition>();
|
||||
_localMemories = new Dictionary<int, MemoryDefinition>();
|
||||
_sharedMemories = new Dictionary<int, MemoryDefinition>();
|
||||
}
|
||||
@@ -40,12 +40,12 @@ namespace Ryujinx.Graphics.Shader.StructuredIr
|
||||
|
||||
public void AddOrUpdateTexture(TextureDefinition definition)
|
||||
{
|
||||
_textures[definition.Binding] = definition;
|
||||
_textures[new(definition.Set, definition.Binding)] = definition;
|
||||
}
|
||||
|
||||
public void AddOrUpdateImage(TextureDefinition definition)
|
||||
{
|
||||
_images[definition.Binding] = definition;
|
||||
_images[new(definition.Set, definition.Binding)] = definition;
|
||||
}
|
||||
|
||||
public int AddLocalMemory(MemoryDefinition definition)
|
||||
|
@@ -169,7 +169,17 @@ namespace Ryujinx.Graphics.Shader.StructuredIr
|
||||
|
||||
AstTextureOperation GetAstTextureOperation(TextureOperation texOp)
|
||||
{
|
||||
return new AstTextureOperation(inst, texOp.Type, texOp.Format, texOp.Flags, texOp.Binding, texOp.SamplerBinding, texOp.Index, sources);
|
||||
return new AstTextureOperation(
|
||||
inst,
|
||||
texOp.Type,
|
||||
texOp.Format,
|
||||
texOp.Flags,
|
||||
texOp.Set,
|
||||
texOp.Binding,
|
||||
texOp.SamplerSet,
|
||||
texOp.SamplerBinding,
|
||||
texOp.Index,
|
||||
sources);
|
||||
}
|
||||
|
||||
int componentsCount = BitOperations.PopCount((uint)operation.Index);
|
||||
|
@@ -4,6 +4,7 @@ namespace Ryujinx.Graphics.Shader
|
||||
{
|
||||
// New fields should be added to the end of the struct to keep disk shader cache compatibility.
|
||||
|
||||
public readonly int Set;
|
||||
public readonly int Binding;
|
||||
|
||||
public readonly SamplerType Type;
|
||||
@@ -18,6 +19,7 @@ namespace Ryujinx.Graphics.Shader
|
||||
public readonly TextureUsageFlags Flags;
|
||||
|
||||
public TextureDescriptor(
|
||||
int set,
|
||||
int binding,
|
||||
SamplerType type,
|
||||
TextureFormat format,
|
||||
@@ -27,6 +29,7 @@ namespace Ryujinx.Graphics.Shader
|
||||
bool separate,
|
||||
TextureUsageFlags flags)
|
||||
{
|
||||
Set = set;
|
||||
Binding = binding;
|
||||
Type = type;
|
||||
Format = format;
|
||||
|
@@ -124,7 +124,7 @@ namespace Ryujinx.Graphics.Shader.Translation
|
||||
this.TextureSample(
|
||||
SamplerType.TextureBuffer,
|
||||
TextureFlags.IntCoords,
|
||||
ResourceManager.Reservations.IndexBufferTextureBinding,
|
||||
ResourceManager.Reservations.GetIndexBufferTextureSetAndBinding(),
|
||||
1,
|
||||
new[] { vertexIndexVr },
|
||||
new[] { this.IAdd(ibBaseOffset, outputVertexOffset) });
|
||||
@@ -145,7 +145,7 @@ namespace Ryujinx.Graphics.Shader.Translation
|
||||
this.TextureSample(
|
||||
SamplerType.TextureBuffer,
|
||||
TextureFlags.IntCoords,
|
||||
ResourceManager.Reservations.TopologyRemapBufferTextureBinding,
|
||||
ResourceManager.Reservations.GetTopologyRemapBufferTextureSetAndBinding(),
|
||||
1,
|
||||
new[] { vertexIndex },
|
||||
new[] { this.IAdd(baseVertex, Const(index)) });
|
||||
|
@@ -618,12 +618,21 @@ namespace Ryujinx.Graphics.Shader.Translation
|
||||
SamplerType type,
|
||||
TextureFormat format,
|
||||
TextureFlags flags,
|
||||
int binding,
|
||||
SetBindingPair setAndBinding,
|
||||
Operand[] sources)
|
||||
{
|
||||
Operand dest = Local();
|
||||
|
||||
context.Add(new TextureOperation(Instruction.ImageAtomic, type, format, flags, binding, 0, new[] { dest }, sources));
|
||||
context.Add(new TextureOperation(
|
||||
Instruction.ImageAtomic,
|
||||
type,
|
||||
format,
|
||||
flags,
|
||||
setAndBinding.SetIndex,
|
||||
setAndBinding.Binding,
|
||||
0,
|
||||
new[] { dest },
|
||||
sources));
|
||||
|
||||
return dest;
|
||||
}
|
||||
@@ -633,12 +642,21 @@ namespace Ryujinx.Graphics.Shader.Translation
|
||||
SamplerType type,
|
||||
TextureFormat format,
|
||||
TextureFlags flags,
|
||||
int binding,
|
||||
SetBindingPair setAndBinding,
|
||||
int compMask,
|
||||
Operand[] dests,
|
||||
Operand[] sources)
|
||||
{
|
||||
context.Add(new TextureOperation(Instruction.ImageLoad, type, format, flags, binding, compMask, dests, sources));
|
||||
context.Add(new TextureOperation(
|
||||
Instruction.ImageLoad,
|
||||
type,
|
||||
format,
|
||||
flags,
|
||||
setAndBinding.SetIndex,
|
||||
setAndBinding.Binding,
|
||||
compMask,
|
||||
dests,
|
||||
sources));
|
||||
}
|
||||
|
||||
public static void ImageStore(
|
||||
@@ -646,10 +664,19 @@ namespace Ryujinx.Graphics.Shader.Translation
|
||||
SamplerType type,
|
||||
TextureFormat format,
|
||||
TextureFlags flags,
|
||||
int binding,
|
||||
SetBindingPair setAndBinding,
|
||||
Operand[] sources)
|
||||
{
|
||||
context.Add(new TextureOperation(Instruction.ImageStore, type, format, flags, binding, 0, null, sources));
|
||||
context.Add(new TextureOperation(
|
||||
Instruction.ImageStore,
|
||||
type,
|
||||
format,
|
||||
flags,
|
||||
setAndBinding.SetIndex,
|
||||
setAndBinding.Binding,
|
||||
0,
|
||||
null,
|
||||
sources));
|
||||
}
|
||||
|
||||
public static Operand IsNan(this EmitterContext context, Operand a, Instruction fpType = Instruction.FP32)
|
||||
@@ -718,13 +745,22 @@ namespace Ryujinx.Graphics.Shader.Translation
|
||||
this EmitterContext context,
|
||||
SamplerType type,
|
||||
TextureFlags flags,
|
||||
int binding,
|
||||
SetBindingPair setAndBinding,
|
||||
int compIndex,
|
||||
Operand[] sources)
|
||||
{
|
||||
Operand dest = Local();
|
||||
|
||||
context.Add(new TextureOperation(Instruction.Lod, type, TextureFormat.Unknown, flags, binding, compIndex, new[] { dest }, sources));
|
||||
context.Add(new TextureOperation(
|
||||
Instruction.Lod,
|
||||
type,
|
||||
TextureFormat.Unknown,
|
||||
flags,
|
||||
setAndBinding.SetIndex,
|
||||
setAndBinding.Binding,
|
||||
compIndex,
|
||||
new[] { dest },
|
||||
sources));
|
||||
|
||||
return dest;
|
||||
}
|
||||
@@ -889,24 +925,42 @@ namespace Ryujinx.Graphics.Shader.Translation
|
||||
this EmitterContext context,
|
||||
SamplerType type,
|
||||
TextureFlags flags,
|
||||
int binding,
|
||||
SetBindingPair setAndBinding,
|
||||
int compMask,
|
||||
Operand[] dests,
|
||||
Operand[] sources)
|
||||
{
|
||||
context.Add(new TextureOperation(Instruction.TextureSample, type, TextureFormat.Unknown, flags, binding, compMask, dests, sources));
|
||||
context.Add(new TextureOperation(
|
||||
Instruction.TextureSample,
|
||||
type,
|
||||
TextureFormat.Unknown,
|
||||
flags,
|
||||
setAndBinding.SetIndex,
|
||||
setAndBinding.Binding,
|
||||
compMask,
|
||||
dests,
|
||||
sources));
|
||||
}
|
||||
|
||||
public static Operand TextureQuerySamples(
|
||||
this EmitterContext context,
|
||||
SamplerType type,
|
||||
TextureFlags flags,
|
||||
int binding,
|
||||
SetBindingPair setAndBinding,
|
||||
Operand[] sources)
|
||||
{
|
||||
Operand dest = Local();
|
||||
|
||||
context.Add(new TextureOperation(Instruction.TextureQuerySamples, type, TextureFormat.Unknown, flags, binding, 0, new[] { dest }, sources));
|
||||
context.Add(new TextureOperation(
|
||||
Instruction.TextureQuerySamples,
|
||||
type,
|
||||
TextureFormat.Unknown,
|
||||
flags,
|
||||
setAndBinding.SetIndex,
|
||||
setAndBinding.Binding,
|
||||
0,
|
||||
new[] { dest },
|
||||
sources));
|
||||
|
||||
return dest;
|
||||
}
|
||||
@@ -915,13 +969,22 @@ namespace Ryujinx.Graphics.Shader.Translation
|
||||
this EmitterContext context,
|
||||
SamplerType type,
|
||||
TextureFlags flags,
|
||||
int binding,
|
||||
SetBindingPair setAndBinding,
|
||||
int compIndex,
|
||||
Operand[] sources)
|
||||
{
|
||||
Operand dest = Local();
|
||||
|
||||
context.Add(new TextureOperation(Instruction.TextureQuerySize, type, TextureFormat.Unknown, flags, binding, compIndex, new[] { dest }, sources));
|
||||
context.Add(new TextureOperation(
|
||||
Instruction.TextureQuerySize,
|
||||
type,
|
||||
TextureFormat.Unknown,
|
||||
flags,
|
||||
setAndBinding.SetIndex,
|
||||
setAndBinding.Binding,
|
||||
compIndex,
|
||||
new[] { dest },
|
||||
sources));
|
||||
|
||||
return dest;
|
||||
}
|
||||
|
@@ -38,6 +38,12 @@ namespace Ryujinx.Graphics.Shader.Translation.Optimizations
|
||||
// If we can't do bindless elimination, remove the texture operation.
|
||||
// Set any destination variables to zero.
|
||||
|
||||
string typeName = texOp.Inst.IsImage()
|
||||
? texOp.Type.ToGlslImageType(texOp.Format.GetComponentType())
|
||||
: texOp.Type.ToGlslTextureType();
|
||||
|
||||
gpuAccessor.Log($"Failed to find handle source for bindless access of type \"{typeName}\".");
|
||||
|
||||
for (int destIndex = 0; destIndex < texOp.DestsCount; destIndex++)
|
||||
{
|
||||
block.Operations.AddBefore(node, new Operation(Instruction.Copy, texOp.GetDest(destIndex), OperandHelper.Const(0)));
|
||||
@@ -62,17 +68,22 @@ namespace Ryujinx.Graphics.Shader.Translation.Optimizations
|
||||
return false;
|
||||
}
|
||||
|
||||
Operand nvHandle = texOp.GetSource(0);
|
||||
Operand bindlessHandle = texOp.GetSource(0);
|
||||
|
||||
if (nvHandle.AsgOp is not Operation handleOp ||
|
||||
handleOp.Inst != Instruction.Load ||
|
||||
(handleOp.StorageKind != StorageKind.Input && handleOp.StorageKind != StorageKind.StorageBuffer))
|
||||
if (bindlessHandle.AsgOp is PhiNode phi)
|
||||
{
|
||||
// Right now, we only allow bindless access when the handle comes from a shader input or storage buffer.
|
||||
// This is an artificial limitation to prevent it from being used in cases where it
|
||||
// would have a large performance impact of loading all textures in the pool.
|
||||
// It might be removed in the future, if we can mitigate the performance impact.
|
||||
for (int srcIndex = 0; srcIndex < phi.SourcesCount; srcIndex++)
|
||||
{
|
||||
Operand phiSource = phi.GetSource(srcIndex);
|
||||
|
||||
if (phiSource.AsgOp is not PhiNode && !IsBindlessAccessAllowed(phiSource))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (!IsBindlessAccessAllowed(bindlessHandle))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -80,8 +91,8 @@ namespace Ryujinx.Graphics.Shader.Translation.Optimizations
|
||||
Operand samplerHandle = OperandHelper.Local();
|
||||
Operand textureIndex = OperandHelper.Local();
|
||||
|
||||
block.Operations.AddBefore(node, new Operation(Instruction.BitwiseAnd, textureHandle, nvHandle, OperandHelper.Const(0xfffff)));
|
||||
block.Operations.AddBefore(node, new Operation(Instruction.ShiftRightU32, samplerHandle, nvHandle, OperandHelper.Const(20)));
|
||||
block.Operations.AddBefore(node, new Operation(Instruction.BitwiseAnd, textureHandle, bindlessHandle, OperandHelper.Const(0xfffff)));
|
||||
block.Operations.AddBefore(node, new Operation(Instruction.ShiftRightU32, samplerHandle, bindlessHandle, OperandHelper.Const(20)));
|
||||
|
||||
int texturePoolLength = Math.Max(BindlessToArray.MinimumArrayLength, gpuAccessor.QueryTextureArrayLengthFromPool());
|
||||
|
||||
@@ -91,7 +102,7 @@ namespace Ryujinx.Graphics.Shader.Translation.Optimizations
|
||||
|
||||
bool hasSampler = !texOp.Inst.IsImage();
|
||||
|
||||
int textureBinding = resourceManager.GetTextureOrImageBinding(
|
||||
SetBindingPair textureSetAndBinding = resourceManager.GetTextureOrImageBinding(
|
||||
texOp.Inst,
|
||||
texOp.Type,
|
||||
texOp.Format,
|
||||
@@ -111,7 +122,7 @@ namespace Ryujinx.Graphics.Shader.Translation.Optimizations
|
||||
|
||||
texOp.InsertSource(1, samplerIndex);
|
||||
|
||||
int samplerBinding = resourceManager.GetTextureOrImageBinding(
|
||||
SetBindingPair samplerSetAndBinding = resourceManager.GetTextureOrImageBinding(
|
||||
texOp.Inst,
|
||||
SamplerType.None,
|
||||
texOp.Format,
|
||||
@@ -120,11 +131,35 @@ namespace Ryujinx.Graphics.Shader.Translation.Optimizations
|
||||
TextureHandle.PackOffsets(0, 0, TextureHandleType.Direct),
|
||||
samplerPoolLength);
|
||||
|
||||
texOp.TurnIntoArray(textureBinding, samplerBinding);
|
||||
texOp.TurnIntoArray(textureSetAndBinding, samplerSetAndBinding);
|
||||
}
|
||||
else
|
||||
{
|
||||
texOp.TurnIntoArray(textureBinding);
|
||||
texOp.TurnIntoArray(textureSetAndBinding);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
private static bool IsBindlessAccessAllowed(Operand nvHandle)
|
||||
{
|
||||
if (nvHandle.Type == OperandType.ConstantBuffer)
|
||||
{
|
||||
// Bindless access with handles from constant buffer is allowed.
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
if (nvHandle.AsgOp is not Operation handleOp ||
|
||||
handleOp.Inst != Instruction.Load ||
|
||||
(handleOp.StorageKind != StorageKind.Input && handleOp.StorageKind != StorageKind.StorageBuffer))
|
||||
{
|
||||
// Right now, we only allow bindless access when the handle comes from a shader input or storage buffer.
|
||||
// This is an artificial limitation to prevent it from being used in cases where it
|
||||
// would have a large performance impact of loading all textures in the pool.
|
||||
// It might be removed in the future, if we can mitigate the performance impact.
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
@@ -445,7 +480,7 @@ namespace Ryujinx.Graphics.Shader.Translation.Optimizations
|
||||
}
|
||||
}
|
||||
|
||||
int binding = resourceManager.GetTextureOrImageBinding(
|
||||
SetBindingPair setAndBinding = resourceManager.GetTextureOrImageBinding(
|
||||
texOp.Inst,
|
||||
texOp.Type,
|
||||
texOp.Format,
|
||||
@@ -453,7 +488,7 @@ namespace Ryujinx.Graphics.Shader.Translation.Optimizations
|
||||
cbufSlot,
|
||||
cbufOffset);
|
||||
|
||||
texOp.SetBinding(binding);
|
||||
texOp.SetBinding(setAndBinding);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@@ -221,7 +221,7 @@ namespace Ryujinx.Graphics.Shader.Translation.Optimizations
|
||||
|
||||
private static void TurnIntoArray(ResourceManager resourceManager, TextureOperation texOp, int cbufSlot, int handleIndex, int length)
|
||||
{
|
||||
int binding = resourceManager.GetTextureOrImageBinding(
|
||||
SetBindingPair setAndBinding = resourceManager.GetTextureOrImageBinding(
|
||||
texOp.Inst,
|
||||
texOp.Type,
|
||||
texOp.Format,
|
||||
@@ -230,7 +230,7 @@ namespace Ryujinx.Graphics.Shader.Translation.Optimizations
|
||||
handleIndex,
|
||||
length);
|
||||
|
||||
texOp.TurnIntoArray(binding);
|
||||
texOp.TurnIntoArray(setAndBinding);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@@ -20,8 +20,8 @@ namespace Ryujinx.Graphics.Shader.Translation
|
||||
private readonly ShaderStage _stage;
|
||||
private readonly string _stagePrefix;
|
||||
|
||||
private readonly int[] _cbSlotToBindingMap;
|
||||
private readonly int[] _sbSlotToBindingMap;
|
||||
private readonly SetBindingPair[] _cbSlotToBindingMap;
|
||||
private readonly SetBindingPair[] _sbSlotToBindingMap;
|
||||
private uint _sbSlotWritten;
|
||||
|
||||
private readonly Dictionary<int, int> _sbSlots;
|
||||
@@ -33,6 +33,7 @@ namespace Ryujinx.Graphics.Shader.Translation
|
||||
|
||||
private struct TextureMeta
|
||||
{
|
||||
public int Set;
|
||||
public int Binding;
|
||||
public bool AccurateType;
|
||||
public SamplerType Type;
|
||||
@@ -64,10 +65,10 @@ namespace Ryujinx.Graphics.Shader.Translation
|
||||
_stage = stage;
|
||||
_stagePrefix = GetShaderStagePrefix(stage);
|
||||
|
||||
_cbSlotToBindingMap = new int[18];
|
||||
_sbSlotToBindingMap = new int[16];
|
||||
_cbSlotToBindingMap.AsSpan().Fill(-1);
|
||||
_sbSlotToBindingMap.AsSpan().Fill(-1);
|
||||
_cbSlotToBindingMap = new SetBindingPair[18];
|
||||
_sbSlotToBindingMap = new SetBindingPair[16];
|
||||
_cbSlotToBindingMap.AsSpan().Fill(new(-1, -1));
|
||||
_sbSlotToBindingMap.AsSpan().Fill(new(-1, -1));
|
||||
|
||||
_sbSlots = new();
|
||||
_sbSlotsReverse = new();
|
||||
@@ -146,16 +147,16 @@ namespace Ryujinx.Graphics.Shader.Translation
|
||||
|
||||
public int GetConstantBufferBinding(int slot)
|
||||
{
|
||||
int binding = _cbSlotToBindingMap[slot];
|
||||
if (binding < 0)
|
||||
SetBindingPair setAndBinding = _cbSlotToBindingMap[slot];
|
||||
if (setAndBinding.Binding < 0)
|
||||
{
|
||||
binding = _gpuAccessor.CreateConstantBufferBinding(slot);
|
||||
_cbSlotToBindingMap[slot] = binding;
|
||||
setAndBinding = _gpuAccessor.CreateConstantBufferBinding(slot);
|
||||
_cbSlotToBindingMap[slot] = setAndBinding;
|
||||
string slotNumber = slot.ToString(CultureInfo.InvariantCulture);
|
||||
AddNewConstantBuffer(binding, $"{_stagePrefix}_c{slotNumber}");
|
||||
AddNewConstantBuffer(setAndBinding.SetIndex, setAndBinding.Binding, $"{_stagePrefix}_c{slotNumber}");
|
||||
}
|
||||
|
||||
return binding;
|
||||
return setAndBinding.Binding;
|
||||
}
|
||||
|
||||
public bool TryGetStorageBufferBinding(int sbCbSlot, int sbCbOffset, bool write, out int binding)
|
||||
@@ -166,14 +167,14 @@ namespace Ryujinx.Graphics.Shader.Translation
|
||||
return false;
|
||||
}
|
||||
|
||||
binding = _sbSlotToBindingMap[slot];
|
||||
SetBindingPair setAndBinding = _sbSlotToBindingMap[slot];
|
||||
|
||||
if (binding < 0)
|
||||
if (setAndBinding.Binding < 0)
|
||||
{
|
||||
binding = _gpuAccessor.CreateStorageBufferBinding(slot);
|
||||
_sbSlotToBindingMap[slot] = binding;
|
||||
setAndBinding = _gpuAccessor.CreateStorageBufferBinding(slot);
|
||||
_sbSlotToBindingMap[slot] = setAndBinding;
|
||||
string slotNumber = slot.ToString(CultureInfo.InvariantCulture);
|
||||
AddNewStorageBuffer(binding, $"{_stagePrefix}_s{slotNumber}");
|
||||
AddNewStorageBuffer(setAndBinding.SetIndex, setAndBinding.Binding, $"{_stagePrefix}_s{slotNumber}");
|
||||
}
|
||||
|
||||
if (write)
|
||||
@@ -181,6 +182,7 @@ namespace Ryujinx.Graphics.Shader.Translation
|
||||
_sbSlotWritten |= 1u << slot;
|
||||
}
|
||||
|
||||
binding = setAndBinding.Binding;
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -208,7 +210,7 @@ namespace Ryujinx.Graphics.Shader.Translation
|
||||
{
|
||||
for (slot = 0; slot < _cbSlotToBindingMap.Length; slot++)
|
||||
{
|
||||
if (_cbSlotToBindingMap[slot] == binding)
|
||||
if (_cbSlotToBindingMap[slot].Binding == binding)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
@@ -218,7 +220,7 @@ namespace Ryujinx.Graphics.Shader.Translation
|
||||
return false;
|
||||
}
|
||||
|
||||
public int GetTextureOrImageBinding(
|
||||
public SetBindingPair GetTextureOrImageBinding(
|
||||
Instruction inst,
|
||||
SamplerType type,
|
||||
TextureFormat format,
|
||||
@@ -240,7 +242,7 @@ namespace Ryujinx.Graphics.Shader.Translation
|
||||
format = TextureFormat.Unknown;
|
||||
}
|
||||
|
||||
int binding = GetTextureOrImageBinding(
|
||||
SetBindingPair setAndBinding = GetTextureOrImageBinding(
|
||||
cbufSlot,
|
||||
handle,
|
||||
arrayLength,
|
||||
@@ -255,10 +257,10 @@ namespace Ryujinx.Graphics.Shader.Translation
|
||||
|
||||
_gpuAccessor.RegisterTexture(handle, cbufSlot);
|
||||
|
||||
return binding;
|
||||
return setAndBinding;
|
||||
}
|
||||
|
||||
private int GetTextureOrImageBinding(
|
||||
private SetBindingPair GetTextureOrImageBinding(
|
||||
int cbufSlot,
|
||||
int handle,
|
||||
int arrayLength,
|
||||
@@ -311,21 +313,38 @@ namespace Ryujinx.Graphics.Shader.Translation
|
||||
UsageFlags = usageFlags,
|
||||
};
|
||||
|
||||
int setIndex;
|
||||
int binding;
|
||||
|
||||
if (dict.TryGetValue(info, out var existingMeta))
|
||||
{
|
||||
dict[info] = MergeTextureMeta(meta, existingMeta);
|
||||
setIndex = existingMeta.Set;
|
||||
binding = existingMeta.Binding;
|
||||
}
|
||||
else
|
||||
{
|
||||
bool isBuffer = (type & SamplerType.Mask) == SamplerType.TextureBuffer;
|
||||
if (arrayLength > 1 && (setIndex = _gpuAccessor.CreateExtraSet()) >= 0)
|
||||
{
|
||||
// We reserved an "extra set" for the array.
|
||||
// In this case the binding is always the first one (0).
|
||||
// Using separate sets for array is better as we need to do less descriptor set updates.
|
||||
|
||||
binding = isImage
|
||||
? _gpuAccessor.CreateImageBinding(arrayLength, isBuffer)
|
||||
: _gpuAccessor.CreateTextureBinding(arrayLength, isBuffer);
|
||||
binding = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
bool isBuffer = (type & SamplerType.Mask) == SamplerType.TextureBuffer;
|
||||
|
||||
SetBindingPair setAndBinding = isImage
|
||||
? _gpuAccessor.CreateImageBinding(arrayLength, isBuffer)
|
||||
: _gpuAccessor.CreateTextureBinding(arrayLength, isBuffer);
|
||||
|
||||
setIndex = setAndBinding.SetIndex;
|
||||
binding = setAndBinding.Binding;
|
||||
}
|
||||
|
||||
meta.Set = setIndex;
|
||||
meta.Binding = binding;
|
||||
|
||||
dict.Add(info, meta);
|
||||
@@ -355,7 +374,7 @@ namespace Ryujinx.Graphics.Shader.Translation
|
||||
}
|
||||
|
||||
var definition = new TextureDefinition(
|
||||
isImage ? 3 : 2,
|
||||
setIndex,
|
||||
binding,
|
||||
arrayLength,
|
||||
separate,
|
||||
@@ -373,11 +392,12 @@ namespace Ryujinx.Graphics.Shader.Translation
|
||||
Properties.AddOrUpdateTexture(definition);
|
||||
}
|
||||
|
||||
return binding;
|
||||
return new SetBindingPair(setIndex, binding);
|
||||
}
|
||||
|
||||
private static TextureMeta MergeTextureMeta(TextureMeta meta, TextureMeta existingMeta)
|
||||
{
|
||||
meta.Set = existingMeta.Set;
|
||||
meta.Binding = existingMeta.Binding;
|
||||
meta.UsageFlags |= existingMeta.UsageFlags;
|
||||
|
||||
@@ -440,11 +460,11 @@ namespace Ryujinx.Graphics.Shader.Translation
|
||||
|
||||
for (int slot = 0; slot < _cbSlotToBindingMap.Length; slot++)
|
||||
{
|
||||
int binding = _cbSlotToBindingMap[slot];
|
||||
SetBindingPair setAndBinding = _cbSlotToBindingMap[slot];
|
||||
|
||||
if (binding >= 0 && _usedConstantBufferBindings.Contains(binding))
|
||||
if (setAndBinding.Binding >= 0 && _usedConstantBufferBindings.Contains(setAndBinding.Binding))
|
||||
{
|
||||
descriptors[descriptorIndex++] = new BufferDescriptor(binding, slot);
|
||||
descriptors[descriptorIndex++] = new BufferDescriptor(setAndBinding.SetIndex, setAndBinding.Binding, slot);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -464,13 +484,13 @@ namespace Ryujinx.Graphics.Shader.Translation
|
||||
|
||||
foreach ((int key, int slot) in _sbSlots)
|
||||
{
|
||||
int binding = _sbSlotToBindingMap[slot];
|
||||
SetBindingPair setAndBinding = _sbSlotToBindingMap[slot];
|
||||
|
||||
if (binding >= 0)
|
||||
if (setAndBinding.Binding >= 0)
|
||||
{
|
||||
(int sbCbSlot, int sbCbOffset) = UnpackSbCbInfo(key);
|
||||
BufferUsageFlags flags = (_sbSlotWritten & (1u << slot)) != 0 ? BufferUsageFlags.Write : BufferUsageFlags.None;
|
||||
descriptors[descriptorIndex++] = new BufferDescriptor(binding, slot, sbCbSlot, sbCbOffset, flags);
|
||||
descriptors[descriptorIndex++] = new BufferDescriptor(setAndBinding.SetIndex, setAndBinding.Binding, slot, sbCbSlot, sbCbOffset, flags);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -507,6 +527,7 @@ namespace Ryujinx.Graphics.Shader.Translation
|
||||
}
|
||||
|
||||
descriptors.Add(new TextureDescriptor(
|
||||
meta.Set,
|
||||
meta.Binding,
|
||||
meta.Type,
|
||||
info.Format,
|
||||
@@ -527,6 +548,7 @@ namespace Ryujinx.Graphics.Shader.Translation
|
||||
}
|
||||
|
||||
descriptors.Add(new TextureDescriptor(
|
||||
meta.Set,
|
||||
meta.Binding,
|
||||
meta.Type,
|
||||
info.Format,
|
||||
@@ -587,24 +609,24 @@ namespace Ryujinx.Graphics.Shader.Translation
|
||||
return false;
|
||||
}
|
||||
|
||||
private void AddNewConstantBuffer(int binding, string name)
|
||||
private void AddNewConstantBuffer(int setIndex, int binding, string name)
|
||||
{
|
||||
StructureType type = new(new[]
|
||||
{
|
||||
new StructureField(AggregateType.Array | AggregateType.Vector4 | AggregateType.FP32, "data", Constants.ConstantBufferSize / 16),
|
||||
});
|
||||
|
||||
Properties.AddOrUpdateConstantBuffer(new(BufferLayout.Std140, 0, binding, name, type));
|
||||
Properties.AddOrUpdateConstantBuffer(new(BufferLayout.Std140, setIndex, binding, name, type));
|
||||
}
|
||||
|
||||
private void AddNewStorageBuffer(int binding, string name)
|
||||
private void AddNewStorageBuffer(int setIndex, int binding, string name)
|
||||
{
|
||||
StructureType type = new(new[]
|
||||
{
|
||||
new StructureField(AggregateType.Array | AggregateType.U32, "data", 0),
|
||||
});
|
||||
|
||||
Properties.AddOrUpdateStorageBuffer(new(BufferLayout.Std430, 1, binding, name, type));
|
||||
Properties.AddOrUpdateStorageBuffer(new(BufferLayout.Std430, setIndex, binding, name, type));
|
||||
}
|
||||
|
||||
public static string GetShaderStagePrefix(ShaderStage stage)
|
||||
|
@@ -11,6 +11,8 @@ namespace Ryujinx.Graphics.Shader.Translation
|
||||
|
||||
public const int MaxVertexBufferTextures = 32;
|
||||
|
||||
private const int TextureSetIndex = 2; // TODO: Get from GPU accessor.
|
||||
|
||||
public int VertexInfoConstantBufferBinding { get; }
|
||||
public int VertexOutputStorageBufferBinding { get; }
|
||||
public int GeometryVertexOutputStorageBufferBinding { get; }
|
||||
@@ -163,6 +165,21 @@ namespace Ryujinx.Graphics.Shader.Translation
|
||||
return _vertexBufferTextureBaseBinding + vaLocation;
|
||||
}
|
||||
|
||||
public SetBindingPair GetVertexBufferTextureSetAndBinding(int vaLocation)
|
||||
{
|
||||
return new SetBindingPair(TextureSetIndex, GetVertexBufferTextureBinding(vaLocation));
|
||||
}
|
||||
|
||||
public SetBindingPair GetIndexBufferTextureSetAndBinding()
|
||||
{
|
||||
return new SetBindingPair(TextureSetIndex, IndexBufferTextureBinding);
|
||||
}
|
||||
|
||||
public SetBindingPair GetTopologyRemapBufferTextureSetAndBinding()
|
||||
{
|
||||
return new SetBindingPair(TextureSetIndex, TopologyRemapBufferTextureBinding);
|
||||
}
|
||||
|
||||
internal bool TryGetOffset(StorageKind storageKind, int location, int component, out int offset)
|
||||
{
|
||||
return _offsets.TryGetValue(new IoDefinition(storageKind, IoVariable.UserDefined, location, component), out offset);
|
||||
|
@@ -182,6 +182,7 @@ namespace Ryujinx.Graphics.Shader.Translation.Transforms
|
||||
texOp.Type,
|
||||
texOp.Format,
|
||||
texOp.Flags,
|
||||
texOp.Set,
|
||||
texOp.Binding,
|
||||
index,
|
||||
new[] { coordSize },
|
||||
@@ -251,6 +252,7 @@ namespace Ryujinx.Graphics.Shader.Translation.Transforms
|
||||
texOp.Type,
|
||||
texOp.Format,
|
||||
texOp.Flags,
|
||||
texOp.Set,
|
||||
texOp.Binding,
|
||||
index,
|
||||
new[] { coordSize },
|
||||
@@ -471,6 +473,7 @@ namespace Ryujinx.Graphics.Shader.Translation.Transforms
|
||||
texOp.Type,
|
||||
texOp.Format,
|
||||
texOp.Flags & ~(TextureFlags.Offset | TextureFlags.Offsets),
|
||||
texOp.Set,
|
||||
texOp.Binding,
|
||||
1 << 3, // W component: i=0, j=0
|
||||
new[] { dests[destIndex++] },
|
||||
@@ -527,6 +530,7 @@ namespace Ryujinx.Graphics.Shader.Translation.Transforms
|
||||
texOp.Type,
|
||||
texOp.Format,
|
||||
texOp.Flags & ~(TextureFlags.Offset | TextureFlags.Offsets),
|
||||
texOp.Set,
|
||||
texOp.Binding,
|
||||
componentIndex,
|
||||
dests,
|
||||
@@ -573,6 +577,7 @@ namespace Ryujinx.Graphics.Shader.Translation.Transforms
|
||||
texOp.Type,
|
||||
texOp.Format,
|
||||
texOp.Flags,
|
||||
texOp.Set,
|
||||
texOp.Binding,
|
||||
index,
|
||||
new[] { texSizes[index] },
|
||||
@@ -603,6 +608,7 @@ namespace Ryujinx.Graphics.Shader.Translation.Transforms
|
||||
texOp.Type,
|
||||
texOp.Format,
|
||||
texOp.Flags,
|
||||
texOp.Set,
|
||||
texOp.Binding,
|
||||
0,
|
||||
new[] { lod },
|
||||
@@ -633,6 +639,7 @@ namespace Ryujinx.Graphics.Shader.Translation.Transforms
|
||||
texOp.Type,
|
||||
texOp.Format,
|
||||
texOp.Flags,
|
||||
texOp.Set,
|
||||
texOp.Binding,
|
||||
index,
|
||||
new[] { texSizes[index] },
|
||||
|
@@ -54,6 +54,7 @@ namespace Ryujinx.Graphics.Shader.Translation.Transforms
|
||||
{
|
||||
bool needsSextNorm = context.Definitions.IsAttributePackedRgb10A2Signed(location);
|
||||
|
||||
SetBindingPair setAndBinding = context.ResourceManager.Reservations.GetVertexBufferTextureSetAndBinding(location);
|
||||
Operand temp = needsSextNorm ? Local() : dest;
|
||||
Operand vertexElemOffset = GenerateVertexOffset(context.ResourceManager, node, location, 0);
|
||||
|
||||
@@ -62,7 +63,8 @@ namespace Ryujinx.Graphics.Shader.Translation.Transforms
|
||||
SamplerType.TextureBuffer,
|
||||
TextureFormat.Unknown,
|
||||
TextureFlags.IntCoords,
|
||||
context.ResourceManager.Reservations.GetVertexBufferTextureBinding(location),
|
||||
setAndBinding.SetIndex,
|
||||
setAndBinding.Binding,
|
||||
1 << component,
|
||||
new[] { temp },
|
||||
new[] { vertexElemOffset }));
|
||||
@@ -75,6 +77,7 @@ namespace Ryujinx.Graphics.Shader.Translation.Transforms
|
||||
}
|
||||
else
|
||||
{
|
||||
SetBindingPair setAndBinding = context.ResourceManager.Reservations.GetVertexBufferTextureSetAndBinding(location);
|
||||
Operand temp = component > 0 ? Local() : dest;
|
||||
Operand vertexElemOffset = GenerateVertexOffset(context.ResourceManager, node, location, component);
|
||||
|
||||
@@ -83,7 +86,8 @@ namespace Ryujinx.Graphics.Shader.Translation.Transforms
|
||||
SamplerType.TextureBuffer,
|
||||
TextureFormat.Unknown,
|
||||
TextureFlags.IntCoords,
|
||||
context.ResourceManager.Reservations.GetVertexBufferTextureBinding(location),
|
||||
setAndBinding.SetIndex,
|
||||
setAndBinding.Binding,
|
||||
1,
|
||||
new[] { temp },
|
||||
new[] { vertexElemOffset }));
|
||||
|
@@ -412,8 +412,8 @@ namespace Ryujinx.Graphics.Shader.Translation
|
||||
|
||||
if (Stage == ShaderStage.Vertex)
|
||||
{
|
||||
int ibBinding = resourceManager.Reservations.IndexBufferTextureBinding;
|
||||
TextureDefinition indexBuffer = new(2, ibBinding, "ib_data", SamplerType.TextureBuffer);
|
||||
SetBindingPair ibSetAndBinding = resourceManager.Reservations.GetIndexBufferTextureSetAndBinding();
|
||||
TextureDefinition indexBuffer = new(ibSetAndBinding.SetIndex, ibSetAndBinding.Binding, "ib_data", SamplerType.TextureBuffer);
|
||||
resourceManager.Properties.AddOrUpdateTexture(indexBuffer);
|
||||
|
||||
int inputMap = _program.AttributeUsage.UsedInputAttributes;
|
||||
@@ -421,8 +421,8 @@ namespace Ryujinx.Graphics.Shader.Translation
|
||||
while (inputMap != 0)
|
||||
{
|
||||
int location = BitOperations.TrailingZeroCount(inputMap);
|
||||
int binding = resourceManager.Reservations.GetVertexBufferTextureBinding(location);
|
||||
TextureDefinition vaBuffer = new(2, binding, $"vb_data{location}", SamplerType.TextureBuffer);
|
||||
SetBindingPair setAndBinding = resourceManager.Reservations.GetVertexBufferTextureSetAndBinding(location);
|
||||
TextureDefinition vaBuffer = new(setAndBinding.SetIndex, setAndBinding.Binding, $"vb_data{location}", SamplerType.TextureBuffer);
|
||||
resourceManager.Properties.AddOrUpdateTexture(vaBuffer);
|
||||
|
||||
inputMap &= ~(1 << location);
|
||||
@@ -430,8 +430,8 @@ namespace Ryujinx.Graphics.Shader.Translation
|
||||
}
|
||||
else if (Stage == ShaderStage.Geometry)
|
||||
{
|
||||
int trbBinding = resourceManager.Reservations.TopologyRemapBufferTextureBinding;
|
||||
TextureDefinition remapBuffer = new(2, trbBinding, "trb_data", SamplerType.TextureBuffer);
|
||||
SetBindingPair trbSetAndBinding = resourceManager.Reservations.GetTopologyRemapBufferTextureSetAndBinding();
|
||||
TextureDefinition remapBuffer = new(trbSetAndBinding.SetIndex, trbSetAndBinding.Binding, "trb_data", SamplerType.TextureBuffer);
|
||||
resourceManager.Properties.AddOrUpdateTexture(remapBuffer);
|
||||
|
||||
int geometryVbOutputSbBinding = resourceManager.Reservations.GeometryVertexOutputStorageBufferBinding;
|
||||
|
@@ -69,17 +69,7 @@ namespace Ryujinx.Graphics.Vulkan
|
||||
}
|
||||
}
|
||||
|
||||
private record struct ArrayRef<T>
|
||||
{
|
||||
public ShaderStage Stage;
|
||||
public T Array;
|
||||
|
||||
public ArrayRef(ShaderStage stage, T array)
|
||||
{
|
||||
Stage = stage;
|
||||
Array = array;
|
||||
}
|
||||
}
|
||||
private readonly record struct ArrayRef<T>(ShaderStage Stage, T Array);
|
||||
|
||||
private readonly VulkanRenderer _gd;
|
||||
private readonly Device _device;
|
||||
@@ -97,6 +87,9 @@ namespace Ryujinx.Graphics.Vulkan
|
||||
private ArrayRef<TextureArray>[] _textureArrayRefs;
|
||||
private ArrayRef<ImageArray>[] _imageArrayRefs;
|
||||
|
||||
private ArrayRef<TextureArray>[] _textureArrayExtraRefs;
|
||||
private ArrayRef<ImageArray>[] _imageArrayExtraRefs;
|
||||
|
||||
private readonly DescriptorBufferInfo[] _uniformBuffers;
|
||||
private readonly DescriptorBufferInfo[] _storageBuffers;
|
||||
private readonly DescriptorImageInfo[] _textures;
|
||||
@@ -152,6 +145,9 @@ namespace Ryujinx.Graphics.Vulkan
|
||||
_textureArrayRefs = Array.Empty<ArrayRef<TextureArray>>();
|
||||
_imageArrayRefs = Array.Empty<ArrayRef<ImageArray>>();
|
||||
|
||||
_textureArrayExtraRefs = Array.Empty<ArrayRef<TextureArray>>();
|
||||
_imageArrayExtraRefs = Array.Empty<ArrayRef<ImageArray>>();
|
||||
|
||||
_uniformBuffers = new DescriptorBufferInfo[Constants.MaxUniformBufferBindings];
|
||||
_storageBuffers = new DescriptorBufferInfo[Constants.MaxStorageBufferBindings];
|
||||
_textures = new DescriptorImageInfo[Constants.MaxTexturesPerStage];
|
||||
@@ -495,25 +491,39 @@ namespace Ryujinx.Graphics.Vulkan
|
||||
|
||||
public void SetTextureArray(CommandBufferScoped cbs, ShaderStage stage, int binding, ITextureArray array)
|
||||
{
|
||||
if (_textureArrayRefs.Length <= binding)
|
||||
{
|
||||
Array.Resize(ref _textureArrayRefs, binding + ArrayGrowthSize);
|
||||
}
|
||||
ref ArrayRef<TextureArray> arrayRef = ref GetArrayRef(ref _textureArrayRefs, binding, ArrayGrowthSize);
|
||||
|
||||
if (_textureArrayRefs[binding].Stage != stage || _textureArrayRefs[binding].Array != array)
|
||||
if (arrayRef.Stage != stage || arrayRef.Array != array)
|
||||
{
|
||||
if (_textureArrayRefs[binding].Array != null)
|
||||
{
|
||||
_textureArrayRefs[binding].Array.Bound = false;
|
||||
}
|
||||
arrayRef.Array?.DecrementBindCount();
|
||||
|
||||
if (array is TextureArray textureArray)
|
||||
{
|
||||
textureArray.Bound = true;
|
||||
textureArray.IncrementBindCount();
|
||||
textureArray.QueueWriteToReadBarriers(cbs, stage.ConvertToPipelineStageFlags());
|
||||
}
|
||||
|
||||
_textureArrayRefs[binding] = new ArrayRef<TextureArray>(stage, array as TextureArray);
|
||||
arrayRef = new ArrayRef<TextureArray>(stage, array as TextureArray);
|
||||
|
||||
SignalDirty(DirtyFlags.Texture);
|
||||
}
|
||||
}
|
||||
|
||||
public void SetTextureArraySeparate(CommandBufferScoped cbs, ShaderStage stage, int setIndex, ITextureArray array)
|
||||
{
|
||||
ref ArrayRef<TextureArray> arrayRef = ref GetArrayRef(ref _textureArrayExtraRefs, setIndex - PipelineBase.DescriptorSetLayouts);
|
||||
|
||||
if (arrayRef.Stage != stage || arrayRef.Array != array)
|
||||
{
|
||||
arrayRef.Array?.DecrementBindCount();
|
||||
|
||||
if (array is TextureArray textureArray)
|
||||
{
|
||||
textureArray.IncrementBindCount();
|
||||
textureArray.QueueWriteToReadBarriers(cbs, stage.ConvertToPipelineStageFlags());
|
||||
}
|
||||
|
||||
arrayRef = new ArrayRef<TextureArray>(stage, array as TextureArray);
|
||||
|
||||
SignalDirty(DirtyFlags.Texture);
|
||||
}
|
||||
@@ -521,30 +531,56 @@ namespace Ryujinx.Graphics.Vulkan
|
||||
|
||||
public void SetImageArray(CommandBufferScoped cbs, ShaderStage stage, int binding, IImageArray array)
|
||||
{
|
||||
if (_imageArrayRefs.Length <= binding)
|
||||
{
|
||||
Array.Resize(ref _imageArrayRefs, binding + ArrayGrowthSize);
|
||||
}
|
||||
ref ArrayRef<ImageArray> arrayRef = ref GetArrayRef(ref _imageArrayRefs, binding, ArrayGrowthSize);
|
||||
|
||||
if (_imageArrayRefs[binding].Stage != stage || _imageArrayRefs[binding].Array != array)
|
||||
if (arrayRef.Stage != stage || arrayRef.Array != array)
|
||||
{
|
||||
if (_imageArrayRefs[binding].Array != null)
|
||||
{
|
||||
_imageArrayRefs[binding].Array.Bound = false;
|
||||
}
|
||||
arrayRef.Array?.DecrementBindCount();
|
||||
|
||||
if (array is ImageArray imageArray)
|
||||
{
|
||||
imageArray.Bound = true;
|
||||
imageArray.IncrementBindCount();
|
||||
imageArray.QueueWriteToReadBarriers(cbs, stage.ConvertToPipelineStageFlags());
|
||||
}
|
||||
|
||||
_imageArrayRefs[binding] = new ArrayRef<ImageArray>(stage, array as ImageArray);
|
||||
arrayRef = new ArrayRef<ImageArray>(stage, array as ImageArray);
|
||||
|
||||
SignalDirty(DirtyFlags.Image);
|
||||
}
|
||||
}
|
||||
|
||||
public void SetImageArraySeparate(CommandBufferScoped cbs, ShaderStage stage, int setIndex, IImageArray array)
|
||||
{
|
||||
ref ArrayRef<ImageArray> arrayRef = ref GetArrayRef(ref _imageArrayExtraRefs, setIndex - PipelineBase.DescriptorSetLayouts);
|
||||
|
||||
if (arrayRef.Stage != stage || arrayRef.Array != array)
|
||||
{
|
||||
arrayRef.Array?.DecrementBindCount();
|
||||
|
||||
if (array is ImageArray imageArray)
|
||||
{
|
||||
imageArray.IncrementBindCount();
|
||||
imageArray.QueueWriteToReadBarriers(cbs, stage.ConvertToPipelineStageFlags());
|
||||
}
|
||||
|
||||
arrayRef = new ArrayRef<ImageArray>(stage, array as ImageArray);
|
||||
|
||||
SignalDirty(DirtyFlags.Image);
|
||||
}
|
||||
}
|
||||
|
||||
private static ref ArrayRef<T> GetArrayRef<T>(ref ArrayRef<T>[] array, int index, int growthSize = 1)
|
||||
{
|
||||
ArgumentOutOfRangeException.ThrowIfNegative(index);
|
||||
|
||||
if (array.Length <= index)
|
||||
{
|
||||
Array.Resize(ref array, index + growthSize);
|
||||
}
|
||||
|
||||
return ref array[index];
|
||||
}
|
||||
|
||||
public void SetUniformBuffers(CommandBuffer commandBuffer, ReadOnlySpan<BufferAssignment> buffers)
|
||||
{
|
||||
for (int i = 0; i < buffers.Length; i++)
|
||||
@@ -594,31 +630,40 @@ namespace Ryujinx.Graphics.Vulkan
|
||||
return;
|
||||
}
|
||||
|
||||
var program = _program;
|
||||
|
||||
if (_dirty.HasFlag(DirtyFlags.Uniform))
|
||||
{
|
||||
if (_program.UsePushDescriptors)
|
||||
if (program.UsePushDescriptors)
|
||||
{
|
||||
UpdateAndBindUniformBufferPd(cbs, pbp);
|
||||
UpdateAndBindUniformBufferPd(cbs);
|
||||
}
|
||||
else
|
||||
{
|
||||
UpdateAndBind(cbs, PipelineBase.UniformSetIndex, pbp);
|
||||
UpdateAndBind(cbs, program, PipelineBase.UniformSetIndex, pbp);
|
||||
}
|
||||
}
|
||||
|
||||
if (_dirty.HasFlag(DirtyFlags.Storage))
|
||||
{
|
||||
UpdateAndBind(cbs, PipelineBase.StorageSetIndex, pbp);
|
||||
UpdateAndBind(cbs, program, PipelineBase.StorageSetIndex, pbp);
|
||||
}
|
||||
|
||||
if (_dirty.HasFlag(DirtyFlags.Texture))
|
||||
{
|
||||
UpdateAndBind(cbs, PipelineBase.TextureSetIndex, pbp);
|
||||
UpdateAndBind(cbs, program, PipelineBase.TextureSetIndex, pbp);
|
||||
}
|
||||
|
||||
if (_dirty.HasFlag(DirtyFlags.Image))
|
||||
{
|
||||
UpdateAndBind(cbs, PipelineBase.ImageSetIndex, pbp);
|
||||
UpdateAndBind(cbs, program, PipelineBase.ImageSetIndex, pbp);
|
||||
}
|
||||
|
||||
if (program.BindingSegments.Length > PipelineBase.DescriptorSetLayouts)
|
||||
{
|
||||
// Program is using extra sets, we need to bind those too.
|
||||
|
||||
BindExtraSets(cbs, program, pbp);
|
||||
}
|
||||
|
||||
_dirty = DirtyFlags.None;
|
||||
@@ -658,9 +703,8 @@ namespace Ryujinx.Graphics.Vulkan
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
private void UpdateAndBind(CommandBufferScoped cbs, int setIndex, PipelineBindPoint pbp)
|
||||
private void UpdateAndBind(CommandBufferScoped cbs, ShaderCollection program, int setIndex, PipelineBindPoint pbp)
|
||||
{
|
||||
var program = _program;
|
||||
var bindingSegments = program.BindingSegments[setIndex];
|
||||
|
||||
if (bindingSegments.Length == 0)
|
||||
@@ -869,7 +913,7 @@ namespace Ryujinx.Graphics.Vulkan
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
private void UpdateAndBindUniformBufferPd(CommandBufferScoped cbs, PipelineBindPoint pbp)
|
||||
private void UpdateAndBindUniformBufferPd(CommandBufferScoped cbs)
|
||||
{
|
||||
int sequence = _pdSequence;
|
||||
var bindingSegments = _program.BindingSegments[PipelineBase.UniformSetIndex];
|
||||
@@ -933,6 +977,56 @@ namespace Ryujinx.Graphics.Vulkan
|
||||
}
|
||||
}
|
||||
|
||||
private void BindExtraSets(CommandBufferScoped cbs, ShaderCollection program, PipelineBindPoint pbp)
|
||||
{
|
||||
for (int setIndex = PipelineBase.DescriptorSetLayouts; setIndex < program.BindingSegments.Length; setIndex++)
|
||||
{
|
||||
var bindingSegments = program.BindingSegments[setIndex];
|
||||
|
||||
if (bindingSegments.Length == 0)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
ResourceBindingSegment segment = bindingSegments[0];
|
||||
|
||||
if (segment.IsArray)
|
||||
{
|
||||
DescriptorSet[] sets = null;
|
||||
|
||||
if (segment.Type == ResourceType.Texture ||
|
||||
segment.Type == ResourceType.Sampler ||
|
||||
segment.Type == ResourceType.TextureAndSampler ||
|
||||
segment.Type == ResourceType.BufferTexture)
|
||||
{
|
||||
sets = _textureArrayExtraRefs[setIndex - PipelineBase.DescriptorSetLayouts].Array.GetDescriptorSets(
|
||||
_device,
|
||||
cbs,
|
||||
_templateUpdater,
|
||||
program,
|
||||
setIndex,
|
||||
_dummyTexture,
|
||||
_dummySampler);
|
||||
}
|
||||
else if (segment.Type == ResourceType.Image || segment.Type == ResourceType.BufferImage)
|
||||
{
|
||||
sets = _imageArrayExtraRefs[setIndex - PipelineBase.DescriptorSetLayouts].Array.GetDescriptorSets(
|
||||
_device,
|
||||
cbs,
|
||||
_templateUpdater,
|
||||
program,
|
||||
setIndex,
|
||||
_dummyTexture);
|
||||
}
|
||||
|
||||
if (sets != null)
|
||||
{
|
||||
_gd.Api.CmdBindDescriptorSets(cbs.CommandBuffer, pbp, _program.PipelineLayout, (uint)setIndex, 1, sets, 0, ReadOnlySpan<uint>.Empty);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void SignalCommandBufferChange()
|
||||
{
|
||||
_updateDescriptorCacheCbIndex = true;
|
||||
|
@@ -2,6 +2,7 @@ using Ryujinx.Graphics.GAL;
|
||||
using Silk.NET.Vulkan;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics;
|
||||
|
||||
namespace Ryujinx.Graphics.Vulkan
|
||||
{
|
||||
@@ -24,12 +25,18 @@ namespace Ryujinx.Graphics.Vulkan
|
||||
|
||||
private HashSet<TextureStorage> _storages;
|
||||
|
||||
private DescriptorSet[] _cachedDescriptorSets;
|
||||
|
||||
private int _cachedCommandBufferIndex;
|
||||
private int _cachedSubmissionCount;
|
||||
|
||||
private ShaderCollection _cachedDscProgram;
|
||||
private int _cachedDscSetIndex;
|
||||
private int _cachedDscIndex;
|
||||
|
||||
private readonly bool _isBuffer;
|
||||
|
||||
public bool Bound;
|
||||
private int _bindCount;
|
||||
|
||||
public ImageArray(VulkanRenderer gd, int size, bool isBuffer)
|
||||
{
|
||||
@@ -97,8 +104,12 @@ namespace Ryujinx.Graphics.Vulkan
|
||||
{
|
||||
_cachedCommandBufferIndex = -1;
|
||||
_storages = null;
|
||||
_cachedDescriptorSets = null;
|
||||
|
||||
_gd.PipelineInternal.ForceImageDirty();
|
||||
if (_bindCount != 0)
|
||||
{
|
||||
_gd.PipelineInternal.ForceImageDirty();
|
||||
}
|
||||
}
|
||||
|
||||
public void QueueWriteToReadBarriers(CommandBufferScoped cbs, PipelineStageFlags stageFlags)
|
||||
@@ -175,5 +186,65 @@ namespace Ryujinx.Graphics.Vulkan
|
||||
|
||||
return bufferTextures;
|
||||
}
|
||||
|
||||
public DescriptorSet[] GetDescriptorSets(
|
||||
Device device,
|
||||
CommandBufferScoped cbs,
|
||||
DescriptorSetTemplateUpdater templateUpdater,
|
||||
ShaderCollection program,
|
||||
int setIndex,
|
||||
TextureView dummyTexture)
|
||||
{
|
||||
if (_cachedDescriptorSets != null)
|
||||
{
|
||||
// We still need to ensure the current command buffer holds a reference to all used textures.
|
||||
|
||||
if (!_isBuffer)
|
||||
{
|
||||
GetImageInfos(_gd, cbs, dummyTexture);
|
||||
}
|
||||
else
|
||||
{
|
||||
GetBufferViews(cbs);
|
||||
}
|
||||
|
||||
return _cachedDescriptorSets;
|
||||
}
|
||||
|
||||
_cachedDscProgram?.ReleaseManualDescriptorSetCollection(_cachedDscSetIndex, _cachedDscIndex);
|
||||
var dsc = program.GetNewManualDescriptorSetCollection(cbs.CommandBufferIndex, setIndex, out _cachedDscIndex).Get(cbs);
|
||||
|
||||
DescriptorSetTemplate template = program.Templates[setIndex];
|
||||
|
||||
DescriptorSetTemplateWriter tu = templateUpdater.Begin(template);
|
||||
|
||||
if (!_isBuffer)
|
||||
{
|
||||
tu.Push(GetImageInfos(_gd, cbs, dummyTexture));
|
||||
}
|
||||
else
|
||||
{
|
||||
tu.Push(GetBufferViews(cbs));
|
||||
}
|
||||
|
||||
var sets = dsc.GetSets();
|
||||
templateUpdater.Commit(_gd, device, sets[0]);
|
||||
_cachedDescriptorSets = sets;
|
||||
_cachedDscProgram = program;
|
||||
_cachedDscSetIndex = setIndex;
|
||||
|
||||
return sets;
|
||||
}
|
||||
|
||||
public void IncrementBindCount()
|
||||
{
|
||||
_bindCount++;
|
||||
}
|
||||
|
||||
public void DecrementBindCount()
|
||||
{
|
||||
int newBindCount = --_bindCount;
|
||||
Debug.Assert(newBindCount >= 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user