mirror of
https://gitlab.freedesktop.org/mesa/mesa.git
synced 2026-05-05 05:18:08 +02:00
v3dv: Implement dual source blending
Reviewed-by: Iago Toral Quiroga <itoral@igalia.com> Part-of: <https://gitlab.freedesktop.org/mesa/mesa/-/merge_requests/33942>
This commit is contained in:
parent
a72be0f720
commit
08c323951b
10 changed files with 136 additions and 14 deletions
|
|
@ -5,3 +5,4 @@ VK_EXT_vertex_input_dynamic_state on panvk
|
|||
VK_EXT_vertex_attribute_divisor on panvk
|
||||
supportsNonZeroFirstInstance on panvk
|
||||
GL_ARB_blend_func_extended on v3d
|
||||
dualSrcBlend on v3dv
|
||||
|
|
|
|||
|
|
@ -586,3 +586,11 @@ ubsan-KHR-GL31.transform_feedback3.multiple_streams,Fail
|
|||
|
||||
# This seems to be working with upstream
|
||||
program@execute@vector-conversion,Fail
|
||||
|
||||
# B10G11R11 Formats have accuracy issues.
|
||||
dEQP-VK.pipeline.monolithic.blend.dual_source.format.b10g11r11_ufloat_pack32.output_variable.states.color_dc_ca_rsub_alpha_dc_s1a_rsub-color_cc_da_min_alpha_ca_1ms1a_max-color_1msc_1mdc_max_alpha_cc_sa_rsub-color_da_o_sub_alpha_z_dc_rsub,Fail
|
||||
dEQP-VK.pipeline.monolithic.blend.dual_source.format.b10g11r11_ufloat_pack32.output_variable.states.color_da_ca_max_alpha_da_1mdc_rsub-color_sa_1msc_sub_alpha_sc_1mca_sub-color_1ms1c_s1c_add_alpha_s1c_dc_rsub-color_da_1mda_add_alpha_s1c_1msa_sub,Fail
|
||||
dEQP-VK.pipeline.monolithic.blend.dual_source.format.b10g11r11_ufloat_pack32.output_variable.states.color_1ms1a_sa_max_alpha_sas_sas_min-color_1ms1c_1msa_sub_alpha_1msc_o_add-color_sa_sa_rsub_alpha_cc_cc_add-color_da_da_add_alpha_s1c_da_add,Fail
|
||||
dEQP-VK.pipeline.monolithic.blend.dual_source.format.b10g11r11_ufloat_pack32.output_array.states.color_dc_ca_rsub_alpha_dc_s1a_rsub-color_cc_da_min_alpha_ca_1ms1a_max-color_1msc_1mdc_max_alpha_cc_sa_rsub-color_da_o_sub_alpha_z_dc_rsub,Fail
|
||||
dEQP-VK.pipeline.monolithic.blend.dual_source.format.b10g11r11_ufloat_pack32.output_array.states.color_da_ca_max_alpha_da_1mdc_rsub-color_sa_1msc_sub_alpha_sc_1mca_sub-color_1ms1c_s1c_add_alpha_s1c_dc_rsub-color_da_1mda_add_alpha_s1c_1msa_sub,Fail
|
||||
dEQP-VK.pipeline.monolithic.blend.dual_source.format.b10g11r11_ufloat_pack32.output_array.states.color_1ms1a_sa_max_alpha_sas_sas_min-color_1ms1c_1msa_sub_alpha_1msc_o_add-color_sa_sa_rsub_alpha_cc_cc_add-color_da_da_add_alpha_s1c_da_add,Fail
|
||||
|
|
|
|||
|
|
@ -454,3 +454,11 @@ KHR-GL31.transform_feedback3.skip_multiple_buffers,Fail
|
|||
|
||||
# This seems to be working with upstream
|
||||
program@execute@vector-conversion,Fail
|
||||
|
||||
# B10G11R11 Formats have accuracy issues.
|
||||
dEQP-VK.pipeline.monolithic.blend.dual_source.format.b10g11r11_ufloat_pack32.output_variable.states.color_dc_ca_rsub_alpha_dc_s1a_rsub-color_cc_da_min_alpha_ca_1ms1a_max-color_1msc_1mdc_max_alpha_cc_sa_rsub-color_da_o_sub_alpha_z_dc_rsub,Fail
|
||||
dEQP-VK.pipeline.monolithic.blend.dual_source.format.b10g11r11_ufloat_pack32.output_variable.states.color_da_ca_max_alpha_da_1mdc_rsub-color_sa_1msc_sub_alpha_sc_1mca_sub-color_1ms1c_s1c_add_alpha_s1c_dc_rsub-color_da_1mda_add_alpha_s1c_1msa_sub,Fail
|
||||
dEQP-VK.pipeline.monolithic.blend.dual_source.format.b10g11r11_ufloat_pack32.output_variable.states.color_1ms1a_sa_max_alpha_sas_sas_min-color_1ms1c_1msa_sub_alpha_1msc_o_add-color_sa_sa_rsub_alpha_cc_cc_add-color_da_da_add_alpha_s1c_da_add,Fail
|
||||
dEQP-VK.pipeline.monolithic.blend.dual_source.format.b10g11r11_ufloat_pack32.output_array.states.color_dc_ca_rsub_alpha_dc_s1a_rsub-color_cc_da_min_alpha_ca_1ms1a_max-color_1msc_1mdc_max_alpha_cc_sa_rsub-color_da_o_sub_alpha_z_dc_rsub,Fail
|
||||
dEQP-VK.pipeline.monolithic.blend.dual_source.format.b10g11r11_ufloat_pack32.output_array.states.color_da_ca_max_alpha_da_1mdc_rsub-color_sa_1msc_sub_alpha_sc_1mca_sub-color_1ms1c_s1c_add_alpha_s1c_dc_rsub-color_da_1mda_add_alpha_s1c_1msa_sub,Fail
|
||||
dEQP-VK.pipeline.monolithic.blend.dual_source.format.b10g11r11_ufloat_pack32.output_array.states.color_1ms1a_sa_max_alpha_sas_sas_min-color_1ms1c_1msa_sub_alpha_1msc_o_add-color_sa_sa_rsub_alpha_cc_cc_add-color_da_da_add_alpha_s1c_da_add,Fail
|
||||
|
|
|
|||
|
|
@ -2400,7 +2400,9 @@ update_gfx_uniform_state(struct v3dv_cmd_buffer *cmd_buffer)
|
|||
V3DV_CMD_DIRTY_DESCRIPTOR_SETS |
|
||||
V3DV_CMD_DIRTY_VIEW_INDEX |
|
||||
V3DV_CMD_DIRTY_DRAW_ID)) ||
|
||||
BITSET_TEST(dyn->dirty, MESA_VK_DYNAMIC_VP_VIEWPORTS);
|
||||
BITSET_TEST(dyn->dirty, MESA_VK_DYNAMIC_VP_VIEWPORTS) ||
|
||||
(pipeline->blend.use_software &&
|
||||
BITSET_TEST(dyn->dirty, MESA_VK_DYNAMIC_CB_BLEND_CONSTANTS));
|
||||
|
||||
if (!dirty_uniform_state)
|
||||
return false;
|
||||
|
|
@ -2411,6 +2413,8 @@ update_gfx_uniform_state(struct v3dv_cmd_buffer *cmd_buffer)
|
|||
const bool has_new_descriptors = dirty & V3DV_CMD_DIRTY_DESCRIPTOR_SETS;
|
||||
const bool has_new_view_index = dirty & V3DV_CMD_DIRTY_VIEW_INDEX;
|
||||
const bool has_new_draw_id = dirty & V3DV_CMD_DIRTY_DRAW_ID;
|
||||
const bool has_new_blend_constants = (pipeline->blend.use_software &&
|
||||
BITSET_TEST(dyn->dirty, MESA_VK_DYNAMIC_CB_BLEND_CONSTANTS));
|
||||
|
||||
/* VK_SHADER_STAGE_FRAGMENT_BIT */
|
||||
const bool has_new_descriptors_fs =
|
||||
|
|
@ -2424,7 +2428,8 @@ update_gfx_uniform_state(struct v3dv_cmd_buffer *cmd_buffer)
|
|||
const bool needs_fs_update = has_new_pipeline ||
|
||||
has_new_view_index ||
|
||||
has_new_push_constants_fs ||
|
||||
has_new_descriptors_fs;
|
||||
has_new_descriptors_fs ||
|
||||
has_new_blend_constants;
|
||||
|
||||
if (needs_fs_update) {
|
||||
struct v3dv_shader_variant *fs_variant =
|
||||
|
|
|
|||
|
|
@ -258,7 +258,7 @@ get_features(const struct v3dv_physical_device *physical_device,
|
|||
.geometryShader = true,
|
||||
.tessellationShader = false,
|
||||
.sampleRateShading = true,
|
||||
.dualSrcBlend = false,
|
||||
.dualSrcBlend = true,
|
||||
.logicOp = true,
|
||||
.multiDrawIndirect = false,
|
||||
.drawIndirectFirstInstance = true,
|
||||
|
|
@ -967,7 +967,7 @@ get_device_properties(const struct v3dv_physical_device *device,
|
|||
/* Fragment limits */
|
||||
.maxFragmentInputComponents = max_varying_components,
|
||||
.maxFragmentOutputAttachments = 4,
|
||||
.maxFragmentDualSrcAttachments = 0,
|
||||
.maxFragmentDualSrcAttachments = 1,
|
||||
.maxFragmentCombinedOutputResources = max_rts +
|
||||
MAX_STORAGE_BUFFERS +
|
||||
MAX_STORAGE_IMAGES,
|
||||
|
|
|
|||
|
|
@ -29,6 +29,7 @@
|
|||
#include "qpu/qpu_disasm.h"
|
||||
|
||||
#include "compiler/nir/nir_builder.h"
|
||||
#include "compiler/nir/nir_lower_blend.h"
|
||||
#include "nir/nir_serialize.h"
|
||||
|
||||
#include "util/shader_stats.h"
|
||||
|
|
@ -39,6 +40,7 @@
|
|||
#include "vk_format.h"
|
||||
#include "vk_nir_convert_ycbcr.h"
|
||||
#include "vk_pipeline.h"
|
||||
#include "vk_blend.h"
|
||||
|
||||
static VkResult
|
||||
compute_vpm_config(struct v3dv_pipeline *pipeline);
|
||||
|
|
@ -1121,7 +1123,9 @@ v3d_fs_key_set_color_attachment(struct v3d_fs_key *key,
|
|||
/* If logic operations are enabled then we might emit color reads and we
|
||||
* need to know the color buffer format and swizzle for that
|
||||
*/
|
||||
if (key->logicop_func != PIPE_LOGICOP_COPY) {
|
||||
if (key->logicop_func != PIPE_LOGICOP_COPY ||
|
||||
p_stage->nir->info.fs.uses_fbfetch_output ||
|
||||
key->software_blend) {
|
||||
/* Framebuffer formats should be single plane */
|
||||
assert(vk_format_get_plane_count(fb_format) == 1);
|
||||
key->color_fmt[index].format = fb_pipe_format;
|
||||
|
|
@ -1130,6 +1134,27 @@ v3d_fs_key_set_color_attachment(struct v3d_fs_key *key,
|
|||
sizeof(key->color_fmt[index].swizzle));
|
||||
}
|
||||
|
||||
if (key->software_blend) {
|
||||
struct vk_color_blend_attachment_state *att =
|
||||
&p_stage->pipeline->dynamic_graphics_state.cb.attachments[index];
|
||||
|
||||
if (att->blend_enable) {
|
||||
key->blend[index].rgb_func = vk_blend_op_to_pipe(att->color_blend_op);
|
||||
key->blend[index].alpha_func = vk_blend_op_to_pipe(att->alpha_blend_op);
|
||||
key->blend[index].rgb_dst_factor = vk_blend_factor_to_pipe(att->dst_color_blend_factor);
|
||||
key->blend[index].alpha_dst_factor = vk_blend_factor_to_pipe(att->dst_alpha_blend_factor);
|
||||
key->blend[index].rgb_src_factor = vk_blend_factor_to_pipe(att->src_color_blend_factor);
|
||||
key->blend[index].alpha_src_factor = vk_blend_factor_to_pipe(att->src_alpha_blend_factor);
|
||||
} else {
|
||||
key->blend[index].rgb_func = PIPE_BLEND_ADD;
|
||||
key->blend[index].alpha_func = PIPE_BLEND_ADD;
|
||||
key->blend[index].rgb_dst_factor = PIPE_BLENDFACTOR_ZERO;
|
||||
key->blend[index].alpha_dst_factor = PIPE_BLENDFACTOR_ZERO;
|
||||
key->blend[index].rgb_src_factor = PIPE_BLENDFACTOR_ONE;
|
||||
key->blend[index].alpha_src_factor = PIPE_BLENDFACTOR_ONE;
|
||||
}
|
||||
}
|
||||
|
||||
const struct util_format_description *desc =
|
||||
vk_format_description(fb_format);
|
||||
|
||||
|
|
@ -1215,6 +1240,8 @@ pipeline_populate_v3d_fs_key(struct v3d_fs_key *key,
|
|||
*/
|
||||
key->swap_color_rb = 0;
|
||||
|
||||
key->software_blend = p_stage->pipeline->blend.use_software;
|
||||
|
||||
for (uint32_t i = 0; i < rendering_info->color_attachment_count; i++) {
|
||||
if (rendering_info->color_attachment_formats[i] == VK_FORMAT_UNDEFINED)
|
||||
continue;
|
||||
|
|
@ -1989,6 +2016,8 @@ pipeline_populate_graphics_key(struct v3dv_pipeline *pipeline,
|
|||
key->sample_alpha_to_one = ms_info->alphaToOneEnable;
|
||||
}
|
||||
|
||||
key->software_blend = pipeline->blend.use_software;
|
||||
|
||||
struct vk_render_pass_state *ri = &pipeline->rendering_info;
|
||||
for (uint32_t i = 0; i < ri->color_attachment_count; i++) {
|
||||
if (ri->color_attachment_formats[i] == VK_FORMAT_UNDEFINED)
|
||||
|
|
@ -2002,7 +2031,8 @@ pipeline_populate_graphics_key(struct v3dv_pipeline *pipeline,
|
|||
/* If logic operations are enabled then we might emit color reads and we
|
||||
* need to know the color buffer format and swizzle for that
|
||||
*/
|
||||
if (key->logicop_func != PIPE_LOGICOP_COPY) {
|
||||
if (key->logicop_func != PIPE_LOGICOP_COPY ||
|
||||
key->software_blend) {
|
||||
/* Framebuffer formats should be single plane */
|
||||
assert(vk_format_get_plane_count(fb_format) == 1);
|
||||
key->color_fmt[i].format = fb_pipe_format;
|
||||
|
|
@ -2011,6 +2041,27 @@ pipeline_populate_graphics_key(struct v3dv_pipeline *pipeline,
|
|||
sizeof(key->color_fmt[i].swizzle));
|
||||
}
|
||||
|
||||
if (key->software_blend) {
|
||||
struct vk_color_blend_attachment_state *att =
|
||||
&pipeline->dynamic_graphics_state.cb.attachments[i];
|
||||
|
||||
if (att->blend_enable) {
|
||||
key->blend[i].rgb_func = vk_blend_op_to_pipe(att->color_blend_op);
|
||||
key->blend[i].alpha_func = vk_blend_op_to_pipe(att->alpha_blend_op);
|
||||
key->blend[i].rgb_dst_factor = vk_blend_factor_to_pipe(att->dst_color_blend_factor);
|
||||
key->blend[i].alpha_dst_factor = vk_blend_factor_to_pipe(att->dst_alpha_blend_factor);
|
||||
key->blend[i].rgb_src_factor = vk_blend_factor_to_pipe(att->src_color_blend_factor);
|
||||
key->blend[i].alpha_src_factor = vk_blend_factor_to_pipe(att->src_alpha_blend_factor);
|
||||
} else {
|
||||
key->blend[i].rgb_func = PIPE_BLEND_ADD;
|
||||
key->blend[i].alpha_func = PIPE_BLEND_ADD;
|
||||
key->blend[i].rgb_dst_factor = PIPE_BLENDFACTOR_ZERO;
|
||||
key->blend[i].alpha_dst_factor = PIPE_BLENDFACTOR_ZERO;
|
||||
key->blend[i].rgb_src_factor = PIPE_BLENDFACTOR_ONE;
|
||||
key->blend[i].alpha_src_factor = PIPE_BLENDFACTOR_ONE;
|
||||
}
|
||||
}
|
||||
|
||||
const struct util_format_description *desc =
|
||||
vk_format_description(fb_format);
|
||||
|
||||
|
|
|
|||
|
|
@ -321,11 +321,20 @@ struct v3dv_pipeline_key {
|
|||
bool msaa;
|
||||
bool sample_alpha_to_coverage;
|
||||
bool sample_alpha_to_one;
|
||||
bool software_blend;
|
||||
uint8_t cbufs;
|
||||
struct {
|
||||
enum pipe_format format;
|
||||
uint8_t swizzle[4];
|
||||
} color_fmt[V3D_MAX_DRAW_BUFFERS];
|
||||
struct {
|
||||
enum pipe_blend_func rgb_func;
|
||||
enum pipe_blendfactor rgb_src_factor;
|
||||
enum pipe_blendfactor rgb_dst_factor;
|
||||
enum pipe_blend_func alpha_func;
|
||||
enum pipe_blendfactor alpha_src_factor;
|
||||
enum pipe_blendfactor alpha_dst_factor;
|
||||
} blend[V3D_MAX_DRAW_BUFFERS];
|
||||
uint8_t f32_color_rb;
|
||||
uint32_t va_swap_rb_mask;
|
||||
bool has_multiview;
|
||||
|
|
@ -2318,7 +2327,12 @@ struct v3dv_pipeline {
|
|||
|
||||
/* Blend state */
|
||||
struct {
|
||||
/* Per-RT bit mask with blend enables */
|
||||
/* In some cases, such as when dual source blend factors are in use, we
|
||||
* fall back to software blend lowering.
|
||||
*/
|
||||
bool use_software;
|
||||
|
||||
/* Per-RT bit mask with blend enables. */
|
||||
uint8_t enables;
|
||||
/* Per-RT prepacked blend config packets */
|
||||
uint8_t cfg[V3D_MAX_DRAW_BUFFERS][V3DV_BLEND_CFG_LENGTH];
|
||||
|
|
|
|||
|
|
@ -670,6 +670,19 @@ v3dv_write_uniforms_wg_offsets(struct v3dv_cmd_buffer *cmd_buffer,
|
|||
v3dv_get_aa_line_width(pipeline, job->cmd_buffer));
|
||||
break;
|
||||
|
||||
case QUNIFORM_BLEND_CONSTANT_R:
|
||||
cl_aligned_f(&uniforms, job->cmd_buffer->vk.dynamic_graphics_state.cb.blend_constants[0]);
|
||||
break;
|
||||
case QUNIFORM_BLEND_CONSTANT_G:
|
||||
cl_aligned_f(&uniforms, job->cmd_buffer->vk.dynamic_graphics_state.cb.blend_constants[1]);
|
||||
break;
|
||||
case QUNIFORM_BLEND_CONSTANT_B:
|
||||
cl_aligned_f(&uniforms, job->cmd_buffer->vk.dynamic_graphics_state.cb.blend_constants[2]);
|
||||
break;
|
||||
case QUNIFORM_BLEND_CONSTANT_A:
|
||||
cl_aligned_f(&uniforms, job->cmd_buffer->vk.dynamic_graphics_state.cb.blend_constants[3]);
|
||||
break;
|
||||
|
||||
default:
|
||||
unreachable("unsupported quniform_contents uniform type\n");
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1617,6 +1617,10 @@ v3dX(cmd_buffer_emit_blend)(struct v3dv_cmd_buffer *cmd_buffer)
|
|||
struct v3dv_pipeline *pipeline = cmd_buffer->state.gfx.pipeline;
|
||||
assert(pipeline);
|
||||
|
||||
/* When using software blend we don't want to enable any blend hardware */
|
||||
if (pipeline->blend.use_software)
|
||||
return;
|
||||
|
||||
const struct v3d_device_info *devinfo = &cmd_buffer->device->devinfo;
|
||||
const uint32_t max_color_rts = V3D_MAX_RENDER_TARGETS(devinfo->ver);
|
||||
|
||||
|
|
|
|||
|
|
@ -27,7 +27,8 @@
|
|||
#include "broadcom/compiler/v3d_compiler.h"
|
||||
|
||||
static uint8_t
|
||||
blend_factor(VkBlendFactor factor, bool dst_alpha_one, bool *needs_constants)
|
||||
blend_factor(VkBlendFactor factor, bool dst_alpha_one, bool *needs_constants,
|
||||
bool *needs_dual_src)
|
||||
{
|
||||
switch (factor) {
|
||||
case VK_BLEND_FACTOR_ZERO:
|
||||
|
|
@ -52,11 +53,17 @@ blend_factor(VkBlendFactor factor, bool dst_alpha_one, bool *needs_constants)
|
|||
case VK_BLEND_FACTOR_ONE_MINUS_DST_ALPHA:
|
||||
return dst_alpha_one ? V3D_BLEND_FACTOR_ZERO :
|
||||
V3D_BLEND_FACTOR_INV_DST_ALPHA;
|
||||
|
||||
/* For dual source blending we need to fallback to software as the hardware
|
||||
* has no support for it.
|
||||
*/
|
||||
case VK_BLEND_FACTOR_SRC1_COLOR:
|
||||
case VK_BLEND_FACTOR_ONE_MINUS_SRC1_COLOR:
|
||||
case VK_BLEND_FACTOR_SRC1_ALPHA:
|
||||
case VK_BLEND_FACTOR_ONE_MINUS_SRC1_ALPHA:
|
||||
unreachable("Invalid blend factor: dual source blending not supported.");
|
||||
assert(needs_dual_src);
|
||||
*needs_dual_src = true;
|
||||
return VK_BLEND_FACTOR_ZERO;
|
||||
default:
|
||||
unreachable("Unknown blend factor.");
|
||||
}
|
||||
|
|
@ -86,6 +93,8 @@ pack_blend(struct v3dv_pipeline *pipeline,
|
|||
assert(ri->color_attachment_count == cb_info->attachmentCount);
|
||||
pipeline->blend.needs_color_constants = false;
|
||||
uint32_t color_write_masks = 0;
|
||||
|
||||
bool needs_dual_src = false;
|
||||
for (uint32_t i = 0; i < ri->color_attachment_count; i++) {
|
||||
const VkPipelineColorBlendAttachmentState *b_state =
|
||||
&cb_info->pAttachments[i];
|
||||
|
|
@ -116,21 +125,29 @@ pack_blend(struct v3dv_pipeline *pipeline,
|
|||
config.color_blend_mode = b_state->colorBlendOp;
|
||||
config.color_blend_dst_factor =
|
||||
blend_factor(b_state->dstColorBlendFactor, dst_alpha_one,
|
||||
&pipeline->blend.needs_color_constants);
|
||||
&pipeline->blend.needs_color_constants,
|
||||
&needs_dual_src);
|
||||
config.color_blend_src_factor =
|
||||
blend_factor(b_state->srcColorBlendFactor, dst_alpha_one,
|
||||
&pipeline->blend.needs_color_constants);
|
||||
&pipeline->blend.needs_color_constants,
|
||||
&needs_dual_src);
|
||||
|
||||
config.alpha_blend_mode = b_state->alphaBlendOp;
|
||||
config.alpha_blend_dst_factor =
|
||||
blend_factor(b_state->dstAlphaBlendFactor, dst_alpha_one,
|
||||
&pipeline->blend.needs_color_constants);
|
||||
&pipeline->blend.needs_color_constants,
|
||||
&needs_dual_src);
|
||||
config.alpha_blend_src_factor =
|
||||
blend_factor(b_state->srcAlphaBlendFactor, dst_alpha_one,
|
||||
&pipeline->blend.needs_color_constants);
|
||||
&pipeline->blend.needs_color_constants,
|
||||
&needs_dual_src);
|
||||
}
|
||||
}
|
||||
|
||||
/* We may want to fallback to software in other cases in the future such
|
||||
* as for formats not supported by the blend hardware.
|
||||
*/
|
||||
pipeline->blend.use_software = V3D_DBG(SOFT_BLEND) || needs_dual_src;
|
||||
pipeline->blend.color_write_masks = color_write_masks;
|
||||
}
|
||||
|
||||
|
|
@ -191,7 +208,8 @@ pack_cfg_bits(struct v3dv_pipeline *pipeline,
|
|||
config.direct3d_provoking_vertex = true;
|
||||
}
|
||||
|
||||
config.blend_enable = pipeline->blend.enables != 0;
|
||||
config.blend_enable = pipeline->blend.enables != 0 &&
|
||||
!pipeline->blend.use_software;
|
||||
|
||||
#if V3D_VERSION >= 71
|
||||
/* From the Vulkan spec:
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue