mirror of
https://github.com/libretro/parallel-gx1.git
synced 2026-11-07 04:26:01 -10:00
Metal: framebuffer fetch again, through rslc's subpass input
The vendored rslc reads a subpassInput and prints it to MSL as the colour attachment's [[color(N)]] value, so the pixel header defines INPUT_ATTACHMENT_BINDING and FB_FETCH_VALUE again and the backend reports framebuffer fetch on Apple GPUs and on the Intel GPUs whose probe draws a pixel that reads back doubled.
This commit is contained in:
1 parent
f073fc9448
commit
e13a260b8c
7 files changed
+240
-17
No files matched your search
+38
-4
@@ -341,6 +341,11 @@ static void pr_type(struct rslc_pr *p, const struct rslc_type *t)
|
||||
pr_s(p, t->kind == RSLC_TY_SAMPLER2DARRAY ? "sampler2DArray"
|
||||
: t->kind == RSLC_TY_SAMPLER2DMSARRAY ? "sampler2DMSArray" : "samplerBuffer");
|
||||
break;
|
||||
case RSLC_TY_SUBPASSINPUT:
|
||||
/* MSL alone prints one: the attachment's value, read as a
|
||||
* fragment input */
|
||||
pr_s(p, "float4");
|
||||
break;
|
||||
case RSLC_TY_IMAGE2D:
|
||||
case RSLC_TY_IMAGE2DARRAY:
|
||||
if (p->hlsl)
|
||||
@@ -436,8 +441,10 @@ static const char *pr_block_instance(struct rslc_pr *p, unsigned block)
|
||||
{
|
||||
const struct rslc_blockdecl *b = &p->c->prog.blocks[block];
|
||||
const char *forced = NULL;
|
||||
/* the frontend's names are for its two blocks; further ones keep theirs */
|
||||
if (p->names && block < 2)
|
||||
/* the frontend's names are for its two blocks; further ones keep
|
||||
* theirs. Without RSLC_EXTENDED every block is one of those two,
|
||||
* so the index test folds away. */
|
||||
if (p->names && (RSLC_MAX_BLOCKS == 2 || block < 2))
|
||||
forced = b->push ? p->names->push_instance : p->names->ubo_instance;
|
||||
if (forced)
|
||||
return forced;
|
||||
@@ -1903,6 +1910,9 @@ static void pr_msl_builtin(struct rslc_pr *p, const struct rslc_node *n)
|
||||
}
|
||||
return;
|
||||
}
|
||||
case RSLC_BFN_SUBPASSLOAD:
|
||||
pr_expr(p, rslc_list_item(p->c, list, 0), PR_PREC_POSTFIX);
|
||||
return;
|
||||
case RSLC_BFN_IMAGESIZE:
|
||||
{
|
||||
const struct rslc_type *it = pr_arg_type(p, list, 0);
|
||||
@@ -2481,7 +2491,7 @@ static void pr_msl_env(struct rslc_pr *p, const struct rslc_func *f, bool decl,
|
||||
continue;
|
||||
}
|
||||
#ifdef RSLC_EXTENDED
|
||||
if (v->storage == RSLC_ST_IMAGE)
|
||||
if (v->storage == RSLC_ST_IMAGE || v->storage == RSLC_ST_SUBPASS)
|
||||
{
|
||||
if (decl)
|
||||
{
|
||||
@@ -2618,7 +2628,7 @@ static void pr_msl_env_mark(struct rslc_pr *p, uint8_t *env, uint32_t node, bool
|
||||
case RSLC_ST_IN: case RSLC_ST_OUT: case RSLC_ST_BUILTIN:
|
||||
case RSLC_ST_GLOBAL: case RSLC_ST_SAMPLER:
|
||||
#ifdef RSLC_EXTENDED
|
||||
case RSLC_ST_IMAGE: case RSLC_ST_SHARED:
|
||||
case RSLC_ST_IMAGE: case RSLC_ST_SHARED: case RSLC_ST_SUBPASS:
|
||||
#endif
|
||||
slot = n->a;
|
||||
break;
|
||||
@@ -6356,6 +6366,21 @@ static bool pr_msl(struct rslc_pr *p, struct rslc_result *result)
|
||||
pr_u(p, pr_msl_index(v->binding));
|
||||
pr_s(p, ")]]");
|
||||
}
|
||||
/* an input attachment is the colour attachment's value on entry */
|
||||
for (i = 1; i < pr->nvars; i++)
|
||||
{
|
||||
const struct rslc_var *v = pr->vars[i];
|
||||
if (v->storage != RSLC_ST_SUBPASS || !menv[i])
|
||||
continue;
|
||||
if (!first)
|
||||
pr_s(p, ", ");
|
||||
first = false;
|
||||
pr_s(p, "float4 ");
|
||||
pr_var_name(p, v);
|
||||
pr_s(p, " [[color(");
|
||||
pr_u(p, v->member);
|
||||
pr_s(p, ")]]");
|
||||
}
|
||||
#endif
|
||||
for (i = 1; i < pr->nvars; i++)
|
||||
{
|
||||
@@ -6636,6 +6661,15 @@ bool rslc_emit_text(struct rslc_ctx *c, struct rslc_result *result)
|
||||
rslc_err(c, p->hlsl ? "hlsl: no geometry stage yet" : "msl: no geometry stage", NULL, 0);
|
||||
return false;
|
||||
}
|
||||
/* an input attachment has a form in MSL alone */
|
||||
if (!p->msl)
|
||||
for (k = 1; k < pr->nvars; k++)
|
||||
if (pr->vars[k]->storage == RSLC_ST_SUBPASS)
|
||||
{
|
||||
rslc_err(c, p->hlsl ? "hlsl: no form of subpassInput" : "glsl: no form of subpassInput",
|
||||
NULL, pr->vars[k]->line);
|
||||
return false;
|
||||
}
|
||||
if (p->hlsl && c->stage == RSLC_STAGE_COMPUTE)
|
||||
{
|
||||
uint32_t k;
|
||||
|
||||
+29
-2
@@ -1698,6 +1698,7 @@ struct rslc_quals
|
||||
bool early_fragment_tests;
|
||||
uint8_t gs_prim; /* RSLC_GS_* named in the layout */
|
||||
uint32_t index;
|
||||
uint32_t input_att; /* input_attachment_index; RSLC_UNSET if absent */
|
||||
uint32_t gs_invocations;
|
||||
uint32_t gs_max_vertices;
|
||||
#endif
|
||||
@@ -2958,6 +2959,7 @@ static bool rslc_p_eval(struct rslc_parser *p, uint32_t e, struct rslc_cval *out
|
||||
* A N Z sampler2DArray, sampler2DMSArray, samplerBuffer
|
||||
* J K image2D, image2DArray; g the gvec4 of the image's base,
|
||||
* matched exactly
|
||||
* P subpassInput
|
||||
* (RSLC_EXTENDED; their overloads are absent otherwise)
|
||||
* M any matrix; Q square matrix; T transposed M result
|
||||
* X any scalar or vector, same type as other X
|
||||
@@ -3075,7 +3077,8 @@ static const struct rslc_bsig rslc_bsigs[] = {
|
||||
{ RSLC_BFN_GROUPMEMORYBARRIER, "groupMemoryBarrier", ":v" },
|
||||
{ RSLC_BFN_IMAGESTORE, "imageStore", "J i2 g:v;K i3 g:v" },
|
||||
{ RSLC_BFN_IMAGELOAD, "imageLoad", "J i2:4;K i3:4" },
|
||||
{ RSLC_BFN_IMAGESIZE, "imageSize", "J:i2;K:i3" }
|
||||
{ RSLC_BFN_IMAGESIZE, "imageSize", "J:i2;K:i3" },
|
||||
{ RSLC_BFN_SUBPASSLOAD, "subpassLoad", "P:4" }
|
||||
#endif
|
||||
};
|
||||
|
||||
@@ -3165,6 +3168,8 @@ static bool rslc_bsig_match_tok(struct rslc_parser *p, const char *tok, unsigned
|
||||
return true;
|
||||
}
|
||||
#ifdef RSLC_EXTENDED
|
||||
else if (len == 1 && tok[0] == 'P')
|
||||
return t->kind == RSLC_TY_SUBPASSINPUT;
|
||||
else if (len == 1 && (tok[0] == 'J' || tok[0] == 'K'))
|
||||
{
|
||||
if (t->kind != (tok[0] == 'J' ? RSLC_TY_IMAGE2D : RSLC_TY_IMAGE2DARRAY))
|
||||
@@ -3261,7 +3266,7 @@ static const struct rslc_type *rslc_bsig_param_type(struct rslc_parser *p,
|
||||
if (len == 1 && (tok[0] == 'S' || tok[0] == 'A' || tok[0] == 'N' || tok[0] == 'Z'))
|
||||
return actual;
|
||||
#ifdef RSLC_EXTENDED
|
||||
if (len == 1 && (tok[0] == 'J' || tok[0] == 'K'))
|
||||
if (len == 1 && (tok[0] == 'J' || tok[0] == 'K' || tok[0] == 'P'))
|
||||
return actual;
|
||||
if (len == 1 && tok[0] == 'g')
|
||||
return actual; /* matched exactly */
|
||||
@@ -4525,6 +4530,7 @@ static bool rslc_p_layout(struct rslc_parser *p, struct rslc_quals *q)
|
||||
else if (len == 12 && !memcmp(s, "local_size_x", 12)) slot = &q->cs_local[0];
|
||||
else if (len == 12 && !memcmp(s, "local_size_y", 12)) slot = &q->cs_local[1];
|
||||
else if (len == 12 && !memcmp(s, "local_size_z", 12)) slot = &q->cs_local[2];
|
||||
else if (len == 22 && !memcmp(s, "input_attachment_index", 22)) slot = &q->input_att;
|
||||
else if (rslc_p_image_format(s, len, &q->img_fmt)) { }
|
||||
#endif
|
||||
else if (len == 7 && !memcmp(s, "index", 5)) { }
|
||||
@@ -4554,6 +4560,9 @@ static bool rslc_p_quals(struct rslc_parser *p, struct rslc_quals *q)
|
||||
{
|
||||
memset(q, 0, sizeof(*q));
|
||||
q->location = q->binding = q->set = q->offset = RSLC_UNSET;
|
||||
#ifdef RSLC_EXTENDED
|
||||
q->input_att = RSLC_UNSET;
|
||||
#endif
|
||||
for (;;)
|
||||
{
|
||||
const struct rslc_tok *t = P_TOK(p);
|
||||
@@ -4657,6 +4666,8 @@ static const struct rslc_type *rslc_p_type_spec(struct rslc_parser *p,
|
||||
ty = rslc_type_sampler2d(p->c, RSLC_BASE_INT);
|
||||
else if (k == RSLC_KW_USAMPLER2D)
|
||||
ty = rslc_type_sampler2d(p->c, RSLC_BASE_UINT);
|
||||
else if (k == RSLC_KW_SUBPASSINPUT)
|
||||
ty = rslc_type_basic(p->c, RSLC_TY_SUBPASSINPUT, RSLC_BASE_FLOAT, 1, 1);
|
||||
else if (k >= RSLC_KW_IMAGE2D && k <= RSLC_KW_UIMAGE2DARRAY)
|
||||
{
|
||||
/* the format is the declaration's layout; it is applied there */
|
||||
@@ -5251,6 +5262,11 @@ static bool rslc_p_params(struct rslc_parser *p, struct rslc_func *f)
|
||||
ty = rslc_p_array_suffix(p, ty);
|
||||
if (!ty)
|
||||
return false;
|
||||
#ifdef RSLC_EXTENDED
|
||||
/* the printers hand it over as the value it reads */
|
||||
if (ty->kind == RSLC_TY_SUBPASSINPUT)
|
||||
return rslc_p_fail(p, "a subpassInput cannot be a parameter", NULL);
|
||||
#endif
|
||||
v = rslc_p_new_var(p, name, ty, line);
|
||||
if (!v)
|
||||
return false;
|
||||
@@ -5930,6 +5946,17 @@ static uint32_t rslc_p_declaration(struct rslc_parser *p, bool global)
|
||||
if (q.writeonly)
|
||||
v->quals |= RSLC_VQ_WRITEONLY;
|
||||
}
|
||||
else if (vt->kind == RSLC_TY_SUBPASSINPUT)
|
||||
{
|
||||
/* an input attachment: the fragment stage's framebuffer read */
|
||||
if (!global || !q.is_uniform || p->c->stage != RSLC_STAGE_FRAGMENT)
|
||||
return rslc_p_fail(p, "a subpassInput must be a fragment stage\'s global uniform", NULL), 0;
|
||||
if (q.input_att == RSLC_UNSET)
|
||||
return rslc_p_fail(p, "a subpassInput needs its input_attachment_index", NULL), 0;
|
||||
v->storage = RSLC_ST_SUBPASS;
|
||||
v->member = q.input_att;
|
||||
v->precision = 0;
|
||||
}
|
||||
else if (q.is_shared)
|
||||
{
|
||||
if (!global || p->c->stage != RSLC_STAGE_COMPUTE)
|
||||
|
||||
+41
@@ -417,6 +417,7 @@ static const char *const rslc_keywords[] = {
|
||||
"sampler2DMSArray", "isampler2DMSArray", "usampler2DMSArray",
|
||||
"samplerBuffer", "isamplerBuffer", "usamplerBuffer",
|
||||
"image2D", "iimage2D", "uimage2D", "image2DArray", "iimage2DArray", "uimage2DArray",
|
||||
"subpassInput",
|
||||
"buffer", "readonly", "writeonly", "coherent", "restrict", "volatile", "shared"
|
||||
#endif
|
||||
};
|
||||
@@ -999,6 +1000,7 @@ enum spv_section
|
||||
#define SPV_CAP_CLIPDISTANCE 32
|
||||
#define SPV_CAP_CULLDISTANCE 33
|
||||
#define SPV_CAP_GEOMETRY 2
|
||||
#define SPV_CAP_INPUTATTACHMENT 40
|
||||
#define SPV_MODEL_VERTEX 0
|
||||
#define SPV_MODEL_FRAGMENT 4
|
||||
#define SPV_MODEL_GEOMETRY 3
|
||||
@@ -1039,6 +1041,7 @@ enum spv_section
|
||||
#define SPV_DEC_INDEX 32
|
||||
#define SPV_DEC_BINDING 33
|
||||
#define SPV_DEC_DESCRIPTORSET 34
|
||||
#define SPV_DEC_INPUTATTACHMENTINDEX 43
|
||||
#define SPV_DEC_OFFSET 35
|
||||
|
||||
#define SPV_BI_POSITION 0
|
||||
@@ -1207,6 +1210,7 @@ struct spv_emit
|
||||
uint32_t cur_label; /* current block's label, 0 = terminated */
|
||||
uint32_t entry_label;
|
||||
bool need_imagequery;
|
||||
bool need_inputattachment;
|
||||
bool need_sampledbuffer;
|
||||
bool need_samplerateshading;
|
||||
bool need_clipdistance;
|
||||
@@ -1577,6 +1581,20 @@ static uint32_t spv_type(struct spv_emit *e, const struct rslc_type *t)
|
||||
ti->img = id;
|
||||
break;
|
||||
}
|
||||
case RSLC_TY_SUBPASSINPUT:
|
||||
{
|
||||
/* Dim SubpassData, Sampled 2, format Unknown */
|
||||
uint32_t s = spv_type(e, rslc_type_basic(e->c, RSLC_TY_SCALAR, RSLC_BASE_FLOAT, 1, 1));
|
||||
if (!s)
|
||||
return 0;
|
||||
ti = &e->tinfo[t->id];
|
||||
w[0] = id; w[1] = s; w[2] = 6; w[3] = 0; w[4] = 0; w[5] = 0; w[6] = 2; w[7] = 0;
|
||||
if (!spv_inst(e, SPV_SEC_TYPES, SpvOpTypeImage, w, 8))
|
||||
return 0;
|
||||
ti->img = id;
|
||||
e->need_inputattachment = true;
|
||||
break;
|
||||
}
|
||||
#endif
|
||||
case RSLC_TY_ARRAY:
|
||||
{
|
||||
@@ -3260,6 +3278,16 @@ static uint32_t spv_builtin_node(struct spv_emit *e, const struct rslc_node *n)
|
||||
case RSLC_BFN_IMAGESIZE:
|
||||
e->need_imagequery = true;
|
||||
return spv_r1(e, SpvOpImageQuerySize, tid, args[0], prec);
|
||||
case RSLC_BFN_SUBPASSLOAD:
|
||||
{
|
||||
/* the fragment's own texel: coordinate (0, 0) */
|
||||
static const uint32_t zero[2] = { 0, 0 };
|
||||
uint32_t used, coord = spv_const_composite(e,
|
||||
rslc_type_basic(e->c, RSLC_TY_VEC, RSLC_BASE_INT, 2, 1), zero, &used);
|
||||
if (!coord)
|
||||
return 0;
|
||||
return spv_r2(e, SpvOpImageRead, tid, args[0], coord, prec);
|
||||
}
|
||||
case RSLC_BFN_EMITVERTEX:
|
||||
case RSLC_BFN_ENDPRIMITIVE:
|
||||
/* no result: the void type's id stands for the expression */
|
||||
@@ -4468,6 +4496,7 @@ static bool spv_global_var(struct spv_emit *e, const struct rslc_var *v)
|
||||
case RSLC_ST_GLOBAL: sc = SPV_SC_PRIVATE; break;
|
||||
#ifdef RSLC_EXTENDED
|
||||
case RSLC_ST_IMAGE: sc = SPV_SC_UNIFORMCONSTANT; break;
|
||||
case RSLC_ST_SUBPASS: sc = SPV_SC_UNIFORMCONSTANT; break;
|
||||
case RSLC_ST_SHARED: sc = SPV_SC_WORKGROUP; break;
|
||||
#endif
|
||||
case RSLC_ST_CONST:
|
||||
@@ -4511,6 +4540,13 @@ static bool spv_global_var(struct spv_emit *e, const struct rslc_var *v)
|
||||
if ((v->quals & RSLC_VQ_READONLY) && !spv_decorate(e, id, SPV_DEC_NONWRITABLE))
|
||||
return false;
|
||||
}
|
||||
if (v->storage == RSLC_ST_SUBPASS)
|
||||
{
|
||||
if (!spv_decorate1(e, id, SPV_DEC_DESCRIPTORSET, v->set == RSLC_UNSET ? 0 : v->set)
|
||||
|| !spv_decorate1(e, id, SPV_DEC_BINDING, v->binding == RSLC_UNSET ? 0 : v->binding)
|
||||
|| !spv_decorate1(e, id, SPV_DEC_INPUTATTACHMENTINDEX, v->member))
|
||||
return false;
|
||||
}
|
||||
#endif
|
||||
if (v->storage == RSLC_ST_SAMPLER)
|
||||
{
|
||||
@@ -5003,6 +5039,11 @@ static bool rslc_emit_spirv(struct rslc_ctx *c, struct rslc_result *result)
|
||||
return false;
|
||||
if (e->need_imagequery && !spv_inst1(e, SPV_SEC_CAPS, SpvOpCapability, SPV_CAP_IMAGEQUERY))
|
||||
return false;
|
||||
#ifdef RSLC_EXTENDED
|
||||
if (e->need_inputattachment
|
||||
&& !spv_inst1(e, SPV_SEC_CAPS, SpvOpCapability, SPV_CAP_INPUTATTACHMENT))
|
||||
return false;
|
||||
#endif
|
||||
if (!spv_inst_str(e, SPV_SEC_CAPS, SpvOpExtInstImport, &e->ext_id, 1, "GLSL.std.450", NULL, 0))
|
||||
return false;
|
||||
if (!spv_inst2(e, SPV_SEC_CAPS, SpvOpMemoryModel, 0 /* Logical */, 1 /* GLSL450 */))
|
||||
|
||||
+12
-4
@@ -219,6 +219,8 @@ enum rslc_kw
|
||||
/* RSLC_EXTENDED image types: float, int, uint of each */
|
||||
RSLC_KW_IMAGE2D, RSLC_KW_IIMAGE2D, RSLC_KW_UIMAGE2D,
|
||||
RSLC_KW_IMAGE2DARRAY, RSLC_KW_IIMAGE2DARRAY, RSLC_KW_UIMAGE2DARRAY,
|
||||
/* RSLC_EXTENDED: a fragment stage's input attachment */
|
||||
RSLC_KW_SUBPASSINPUT,
|
||||
/* RSLC_EXTENDED qualifiers */
|
||||
RSLC_KW_BUFFER, RSLC_KW_READONLY, RSLC_KW_WRITEONLY, RSLC_KW_COHERENT,
|
||||
RSLC_KW_RESTRICT, RSLC_KW_VOLATILE, RSLC_KW_SHARED,
|
||||
@@ -249,7 +251,9 @@ enum rslc_tkind
|
||||
RSLC_TY_SAMPLERBUFFER,
|
||||
/* RSLC_EXTENDED storage images; cols is the RSLC_IMGFMT_* */
|
||||
RSLC_TY_IMAGE2D,
|
||||
RSLC_TY_IMAGE2DARRAY
|
||||
RSLC_TY_IMAGE2DARRAY,
|
||||
/* RSLC_EXTENDED: a float input attachment */
|
||||
RSLC_TY_SUBPASSINPUT
|
||||
};
|
||||
|
||||
#define RSLC_TY_IS_IMAGE(k) ((k) == RSLC_TY_IMAGE2D || (k) == RSLC_TY_IMAGE2DARRAY)
|
||||
@@ -274,7 +278,7 @@ enum rslc_tkind
|
||||
#define RSLC_IMGFMT_R32UI 33
|
||||
|
||||
/* The last keyword that names a type. */
|
||||
#define RSLC_KW_LAST_TYPE RSLC_KW_UIMAGE2DARRAY
|
||||
#define RSLC_KW_LAST_TYPE RSLC_KW_SUBPASSINPUT
|
||||
|
||||
/* Every sampler kind: sampler2D, and the RSLC_EXTENDED ones. */
|
||||
#define RSLC_TY_IS_SAMPLER(k) ((k) == RSLC_TY_SAMPLER2D \
|
||||
@@ -326,7 +330,9 @@ enum rslc_storage
|
||||
RSLC_ST_MEMBER, /* a member of an unnamed block, visible bare */
|
||||
RSLC_ST_BUILTIN, /* gl_Position and friends */
|
||||
RSLC_ST_SHARED, /* RSLC_EXTENDED: compute workgroup memory */
|
||||
RSLC_ST_IMAGE /* RSLC_EXTENDED: uniform image2D and the like */
|
||||
RSLC_ST_IMAGE, /* RSLC_EXTENDED: uniform image2D and the like */
|
||||
RSLC_ST_SUBPASS /* RSLC_EXTENDED: uniform subpassInput; member is
|
||||
* its input_attachment_index */
|
||||
};
|
||||
|
||||
#define RSLC_DIR_IN 0
|
||||
@@ -364,7 +370,8 @@ struct rslc_var
|
||||
uint32_t binding;
|
||||
uint32_t set;
|
||||
uint32_t block; /* RSLC_ST_MEMBER / BLOCK: block index */
|
||||
uint32_t member; /* RSLC_ST_MEMBER: field index */
|
||||
uint32_t member; /* RSLC_ST_MEMBER: field index; SUBPASS:
|
||||
* input_attachment_index */
|
||||
uint8_t storage; /* enum rslc_storage */
|
||||
uint8_t dir; /* RSLC_DIR_* for params */
|
||||
uint8_t interp;
|
||||
@@ -583,6 +590,7 @@ enum rslc_bfn
|
||||
RSLC_BFN_BARRIER, RSLC_BFN_MEMORYBARRIER, RSLC_BFN_MEMORYBARRIERSHARED,
|
||||
RSLC_BFN_MEMORYBARRIERBUFFER, RSLC_BFN_MEMORYBARRIERIMAGE, RSLC_BFN_GROUPMEMORYBARRIER,
|
||||
RSLC_BFN_IMAGESTORE, RSLC_BFN_IMAGELOAD, RSLC_BFN_IMAGESIZE,
|
||||
RSLC_BFN_SUBPASSLOAD, /* RSLC_EXTENDED, fragment */
|
||||
RSLC_BFN_COUNT
|
||||
};
|
||||
|
||||
|
||||
@@ -94,6 +94,115 @@ void Metal::Util::PopulateBackendInfoAdapters(BackendInfo* backend_info,
|
||||
}
|
||||
}
|
||||
|
||||
#if TARGET_OS_OSX
|
||||
/* Some Intel GPUs fetch from the framebuffer though no feature set says
|
||||
* so, and others build the pipeline but leave the fetch out: draw one
|
||||
* pixel whose shader doubles what it reads, and check it doubled. */
|
||||
static bool DetectIntelGPUFBFetch(id<MTLDevice> dev)
|
||||
{
|
||||
static const char shader[] =
|
||||
"vertex float4 fs_triangle(uint vid [[vertex_id]]) {\n"
|
||||
" return float4(vid & 1 ? 3 : -1, vid & 2 ? 3 : -1, 0, 1);\n"
|
||||
"}\n"
|
||||
"fragment float4 fbfetch_test(float4 in [[color(0), raster_order_group(0)]]) {\n"
|
||||
" return in * 2;\n"
|
||||
"}\n";
|
||||
const u32 px_in = 0x11223344;
|
||||
u32 px_out = 0;
|
||||
bool ok = false;
|
||||
id<MTLLibrary> lib;
|
||||
id<MTLFunction> vs;
|
||||
id<MTLFunction> fs;
|
||||
MTLRenderPipelineDescriptor* pdesc;
|
||||
id<MTLRenderPipelineState> pipe = nil;
|
||||
id<MTLBuffer> buf = nil;
|
||||
MTLTextureDescriptor* tdesc;
|
||||
id<MTLTexture> tex = nil;
|
||||
id<MTLCommandQueue> q = nil;
|
||||
id<MTLCommandBuffer> cmdbuf;
|
||||
id<MTLBlitCommandEncoder> blit;
|
||||
MTLRenderPassDescriptor* rpdesc;
|
||||
id<MTLRenderCommandEncoder> renc;
|
||||
|
||||
lib = [dev newLibraryWithSource:[NSString stringWithUTF8String:shader] options:nil error:nil];
|
||||
if (!lib)
|
||||
return false;
|
||||
vs = [lib newFunctionWithName:@"fs_triangle"];
|
||||
fs = [lib newFunctionWithName:@"fbfetch_test"];
|
||||
pdesc = [MTLRenderPipelineDescriptor new];
|
||||
[pdesc setVertexFunction:vs];
|
||||
[pdesc setFragmentFunction:fs];
|
||||
[[pdesc colorAttachments][0] setPixelFormat:MTLPixelFormatRGBA8Unorm];
|
||||
if (vs && fs)
|
||||
pipe = [dev newRenderPipelineStateWithDescriptor:pdesc error:nil];
|
||||
if (pipe)
|
||||
{
|
||||
buf = [dev newBufferWithLength:4 options:MTLResourceStorageModeShared];
|
||||
memcpy([buf contents], &px_in, sizeof(px_in));
|
||||
tdesc = [MTLTextureDescriptor texture2DDescriptorWithPixelFormat:MTLPixelFormatRGBA8Unorm
|
||||
width:1
|
||||
height:1
|
||||
mipmapped:false];
|
||||
[tdesc setUsage:MTLTextureUsageRenderTarget];
|
||||
tex = [dev newTextureWithDescriptor:tdesc];
|
||||
q = [dev newCommandQueue];
|
||||
cmdbuf = [q commandBuffer];
|
||||
|
||||
blit = [cmdbuf blitCommandEncoder];
|
||||
[blit copyFromBuffer:buf
|
||||
sourceOffset:0
|
||||
sourceBytesPerRow:4
|
||||
sourceBytesPerImage:4
|
||||
sourceSize:MTLSizeMake(1, 1, 1)
|
||||
toTexture:tex
|
||||
destinationSlice:0
|
||||
destinationLevel:0
|
||||
destinationOrigin:MTLOriginMake(0, 0, 0)];
|
||||
[blit endEncoding];
|
||||
|
||||
rpdesc = [MTLRenderPassDescriptor new];
|
||||
[[rpdesc colorAttachments][0] setTexture:tex];
|
||||
[[rpdesc colorAttachments][0] setLoadAction:MTLLoadActionLoad];
|
||||
[[rpdesc colorAttachments][0] setStoreAction:MTLStoreActionStore];
|
||||
renc = [cmdbuf renderCommandEncoderWithDescriptor:rpdesc];
|
||||
[renc setRenderPipelineState:pipe];
|
||||
[renc drawPrimitives:MTLPrimitiveTypeTriangle vertexStart:0 vertexCount:3];
|
||||
[renc endEncoding];
|
||||
[rpdesc release];
|
||||
|
||||
blit = [cmdbuf blitCommandEncoder];
|
||||
[blit copyFromTexture:tex
|
||||
sourceSlice:0
|
||||
sourceLevel:0
|
||||
sourceOrigin:MTLOriginMake(0, 0, 0)
|
||||
sourceSize:MTLSizeMake(1, 1, 1)
|
||||
toBuffer:buf
|
||||
destinationOffset:0
|
||||
destinationBytesPerRow:4
|
||||
destinationBytesPerImage:4];
|
||||
[blit endEncoding];
|
||||
|
||||
[cmdbuf commit];
|
||||
[cmdbuf waitUntilCompleted];
|
||||
|
||||
memcpy(&px_out, [buf contents], sizeof(px_out));
|
||||
ok = [cmdbuf status] == MTLCommandBufferStatusCompleted;
|
||||
}
|
||||
|
||||
[q release];
|
||||
[tex release];
|
||||
[buf release];
|
||||
[pipe release];
|
||||
[pdesc release];
|
||||
[fs release];
|
||||
[vs release];
|
||||
[lib release];
|
||||
|
||||
/* Skylake and later double it; Broadwell leaves it, Haswell blackens it */
|
||||
return ok && px_out == 0x22446688;
|
||||
}
|
||||
#endif
|
||||
|
||||
void Metal::Util::PopulateBackendInfoFeatures(const VideoConfig& config, BackendInfo* backend_info,
|
||||
id<MTLDevice> device)
|
||||
{
|
||||
@@ -152,9 +261,11 @@ void Metal::Util::PopulateBackendInfoFeatures(const VideoConfig& config, Backend
|
||||
break;
|
||||
}
|
||||
|
||||
/* rslc has no form of a subpass input: blending is not emulated
|
||||
* through framebuffer fetch */
|
||||
backend_info->bSupportsFramebufferFetch = false;
|
||||
backend_info->bSupportsFramebufferFetch = [device supportsFamily:MTLGPUFamilyApple1];
|
||||
#if TARGET_OS_OSX
|
||||
if (vendor == DriverDetails::VENDOR_INTEL)
|
||||
backend_info->bSupportsFramebufferFetch |= DetectIntelGPUFBFetch(device);
|
||||
#endif
|
||||
|
||||
if (DriverDetails::HasBug(DriverDetails::BUG_BROKEN_DYNAMIC_SAMPLER_INDEXING))
|
||||
backend_info->bSupportsDynamicSamplerIndexing = false;
|
||||
@@ -268,6 +379,10 @@ static const std::string_view PIXEL_SHADER_HEADER = R"(
|
||||
#define FORCE_EARLY_Z layout(early_fragment_tests) in
|
||||
#define UBO_BINDING(packing, x) layout(packing, binding = ((x) - 1))
|
||||
#define SSBO_BINDING(x) layout(std430, binding = ((x) + 2))
|
||||
#define INPUT_ATTACHMENT_BINDING(x, y, z) layout(set = x, binding = y, input_attachment_index = z)
|
||||
|
||||
// Metal framebuffer fetch helpers.
|
||||
#define FB_FETCH_VALUE subpassLoad(in_ocol0)
|
||||
|
||||
// hlsl to glsl function translation
|
||||
#define API_METAL 1
|
||||
|
||||
@@ -831,8 +831,7 @@ ShaderCode GeneratePixelShaderCode(APIType api_type, const ShaderHostConfig& hos
|
||||
|
||||
if (use_framebuffer_fetch)
|
||||
{
|
||||
// A subpass input for the framebuffer read; no backend reports framebuffer fetch
|
||||
// here while rslc has no form of one.
|
||||
// rslc prints a subpass input as Metal's framebuffer fetch.
|
||||
out.Write("INPUT_ATTACHMENT_BINDING(0, 0, 0) uniform subpassInput in_ocol0;\n");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -98,8 +98,7 @@ ShaderCode GenPixelShader(APIType api_type, const ShaderHostConfig& host_config,
|
||||
|
||||
if (use_framebuffer_fetch)
|
||||
{
|
||||
// A subpass input for the framebuffer read; no backend reports framebuffer fetch
|
||||
// here while rslc has no form of one.
|
||||
// rslc prints a subpass input as Metal's framebuffer fetch.
|
||||
out.Write("INPUT_ATTACHMENT_BINDING(0, 0, 0) uniform subpassInput in_ocol0;\n");
|
||||
}
|
||||
}
|
||||
|
||||
Reference in new issue
Block a user