mirror of
https://github.com/KhronosGroup/SPIRV-Tools
synced 2024-11-26 13:20:05 +00:00
Added Vulkan-specifc checks to image validation
Implemented Vulkan-specific rules: - OpTypeImage must declare a scalar 32-bit float or 32-bit integer type for the “Sampled Type”. - OpSampledImage must only consume an “Image” operand whose type has its “Sampled” operand set to 1.
This commit is contained in:
parent
c4835e1bd8
commit
bdc78377bc
@ -146,3 +146,28 @@ bool spvParseTargetEnv(const char* s, spv_target_env* env) {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool spvIsVulkanEnv(spv_target_env env) {
|
||||||
|
switch (env) {
|
||||||
|
case SPV_ENV_UNIVERSAL_1_0:
|
||||||
|
case SPV_ENV_OPENCL_1_2:
|
||||||
|
case SPV_ENV_OPENCL_EMBEDDED_1_2:
|
||||||
|
case SPV_ENV_OPENCL_2_0:
|
||||||
|
case SPV_ENV_OPENCL_EMBEDDED_2_0:
|
||||||
|
case SPV_ENV_OPENCL_2_1:
|
||||||
|
case SPV_ENV_OPENCL_EMBEDDED_2_1:
|
||||||
|
case SPV_ENV_OPENGL_4_0:
|
||||||
|
case SPV_ENV_OPENGL_4_1:
|
||||||
|
case SPV_ENV_OPENGL_4_2:
|
||||||
|
case SPV_ENV_OPENGL_4_3:
|
||||||
|
case SPV_ENV_OPENGL_4_5:
|
||||||
|
case SPV_ENV_UNIVERSAL_1_1:
|
||||||
|
case SPV_ENV_UNIVERSAL_1_2:
|
||||||
|
case SPV_ENV_OPENCL_2_2:
|
||||||
|
case SPV_ENV_OPENCL_EMBEDDED_2_2:
|
||||||
|
return false;
|
||||||
|
case SPV_ENV_VULKAN_1_0:
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
@ -21,4 +21,7 @@
|
|||||||
// false and sets *env to SPV_ENV_UNIVERSAL_1_0.
|
// false and sets *env to SPV_ENV_UNIVERSAL_1_0.
|
||||||
bool spvParseTargetEnv(const char* s, spv_target_env* env);
|
bool spvParseTargetEnv(const char* s, spv_target_env* env);
|
||||||
|
|
||||||
|
// Returns true if |env| is a VULKAN environment, false otherwise.
|
||||||
|
bool spvIsVulkanEnv(spv_target_env env);
|
||||||
|
|
||||||
#endif // LIBSPIRV_SPIRV_TARGET_ENV_H_
|
#endif // LIBSPIRV_SPIRV_TARGET_ENV_H_
|
||||||
|
@ -18,6 +18,7 @@
|
|||||||
|
|
||||||
#include "diagnostic.h"
|
#include "diagnostic.h"
|
||||||
#include "opcode.h"
|
#include "opcode.h"
|
||||||
|
#include "spirv_target_env.h"
|
||||||
#include "val/instruction.h"
|
#include "val/instruction.h"
|
||||||
#include "val/validation_state.h"
|
#include "val/validation_state.h"
|
||||||
|
|
||||||
@ -687,6 +688,16 @@ spv_result_t ImagePass(ValidationState_t& _,
|
|||||||
<< "OpTypeImage: corrupt definition";
|
<< "OpTypeImage: corrupt definition";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (spvIsVulkanEnv(_.context()->target_env)) {
|
||||||
|
if ((!_.IsFloatScalarType(info.sampled_type) &&
|
||||||
|
!_.IsIntScalarType(info.sampled_type)) ||
|
||||||
|
32 != _.GetBitWidth(info.sampled_type)) {
|
||||||
|
return _.diag(SPV_ERROR_INVALID_DATA)
|
||||||
|
<< spvOpcodeString(opcode)
|
||||||
|
<< ": expected Sampled Type to be a 32-bit int or float "
|
||||||
|
"scalar type for Vulkan environment";
|
||||||
|
}
|
||||||
|
} else {
|
||||||
const SpvOp sampled_type_opcode = _.GetIdOpcode(info.sampled_type);
|
const SpvOp sampled_type_opcode = _.GetIdOpcode(info.sampled_type);
|
||||||
if (sampled_type_opcode != SpvOpTypeVoid &&
|
if (sampled_type_opcode != SpvOpTypeVoid &&
|
||||||
sampled_type_opcode != SpvOpTypeInt &&
|
sampled_type_opcode != SpvOpTypeInt &&
|
||||||
@ -696,6 +707,7 @@ spv_result_t ImagePass(ValidationState_t& _,
|
|||||||
<< ": expected Sampled Type to be either void or numerical "
|
<< ": expected Sampled Type to be either void or numerical "
|
||||||
<< "scalar type";
|
<< "scalar type";
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Dim is checked elsewhere.
|
// Dim is checked elsewhere.
|
||||||
|
|
||||||
@ -776,11 +788,20 @@ spv_result_t ImagePass(ValidationState_t& _,
|
|||||||
// TODO(atgoo@github.com) Check compatibility of result type and received
|
// TODO(atgoo@github.com) Check compatibility of result type and received
|
||||||
// image.
|
// image.
|
||||||
|
|
||||||
|
if (spvIsVulkanEnv(_.context()->target_env)) {
|
||||||
|
if (info.sampled != 1) {
|
||||||
|
return _.diag(SPV_ERROR_INVALID_DATA)
|
||||||
|
<< "Expected Image 'Sampled' parameter to be 1 for Vulkan "
|
||||||
|
"environment: "
|
||||||
|
<< spvOpcodeString(opcode);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
if (info.sampled != 0 && info.sampled != 1) {
|
if (info.sampled != 0 && info.sampled != 1) {
|
||||||
return _.diag(SPV_ERROR_INVALID_DATA)
|
return _.diag(SPV_ERROR_INVALID_DATA)
|
||||||
<< "Expected Image 'Sampled' parameter to be 0 or 1: "
|
<< "Expected Image 'Sampled' parameter to be 0 or 1: "
|
||||||
<< spvOpcodeString(opcode);
|
<< spvOpcodeString(opcode);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (info.dim == SpvDimSubpassData) {
|
if (info.dim == SpvDimSubpassData) {
|
||||||
return _.diag(SPV_ERROR_INVALID_DATA)
|
return _.diag(SPV_ERROR_INVALID_DATA)
|
||||||
|
@ -31,21 +31,25 @@ using ValidateImage = spvtest::ValidateBase<bool>;
|
|||||||
std::string GenerateShaderCode(
|
std::string GenerateShaderCode(
|
||||||
const std::string& body,
|
const std::string& body,
|
||||||
const std::string& capabilities_and_extensions = "",
|
const std::string& capabilities_and_extensions = "",
|
||||||
const std::string& execution_model = "Fragment") {
|
const std::string& execution_model = "Fragment",
|
||||||
|
const spv_target_env env = SPV_ENV_UNIVERSAL_1_0) {
|
||||||
std::ostringstream ss;
|
std::ostringstream ss;
|
||||||
ss << R"(
|
ss << R"(
|
||||||
OpCapability Float16
|
|
||||||
OpCapability Shader
|
OpCapability Shader
|
||||||
OpCapability InputAttachment
|
OpCapability InputAttachment
|
||||||
OpCapability ImageGatherExtended
|
OpCapability ImageGatherExtended
|
||||||
OpCapability MinLod
|
OpCapability MinLod
|
||||||
OpCapability Sampled1D
|
OpCapability Sampled1D
|
||||||
OpCapability SampledRect
|
|
||||||
OpCapability ImageQuery
|
OpCapability ImageQuery
|
||||||
OpCapability Int64
|
OpCapability Int64
|
||||||
|
OpCapability Float64
|
||||||
OpCapability SparseResidency
|
OpCapability SparseResidency
|
||||||
)";
|
)";
|
||||||
|
|
||||||
|
if (env == SPV_ENV_UNIVERSAL_1_0) {
|
||||||
|
ss << "OpCapability SampledRect\n";
|
||||||
|
}
|
||||||
|
|
||||||
ss << capabilities_and_extensions;
|
ss << capabilities_and_extensions;
|
||||||
ss << "OpMemoryModel Logical GLSL450\n";
|
ss << "OpMemoryModel Logical GLSL450\n";
|
||||||
ss << "OpEntryPoint " << execution_model << " %main \"main\"\n";
|
ss << "OpEntryPoint " << execution_model << " %main \"main\"\n";
|
||||||
@ -54,8 +58,8 @@ OpCapability SparseResidency
|
|||||||
%void = OpTypeVoid
|
%void = OpTypeVoid
|
||||||
%func = OpTypeFunction %void
|
%func = OpTypeFunction %void
|
||||||
%bool = OpTypeBool
|
%bool = OpTypeBool
|
||||||
%f16 = OpTypeFloat 16
|
|
||||||
%f32 = OpTypeFloat 32
|
%f32 = OpTypeFloat 32
|
||||||
|
%f64 = OpTypeFloat 64
|
||||||
%u32 = OpTypeInt 32 0
|
%u32 = OpTypeInt 32 0
|
||||||
%s32 = OpTypeInt 32 1
|
%s32 = OpTypeInt 32 1
|
||||||
%u64 = OpTypeInt 64 0
|
%u64 = OpTypeInt 64 0
|
||||||
@ -69,15 +73,15 @@ OpCapability SparseResidency
|
|||||||
%s32vec4 = OpTypeVector %s32 4
|
%s32vec4 = OpTypeVector %s32 4
|
||||||
%f32vec4 = OpTypeVector %f32 4
|
%f32vec4 = OpTypeVector %f32 4
|
||||||
|
|
||||||
%f16_0 = OpConstant %f16 0
|
|
||||||
%f16_1 = OpConstant %f16 1
|
|
||||||
|
|
||||||
%f32_0 = OpConstant %f32 0
|
%f32_0 = OpConstant %f32 0
|
||||||
%f32_1 = OpConstant %f32 1
|
%f32_1 = OpConstant %f32 1
|
||||||
%f32_0_5 = OpConstant %f32 0.5
|
%f32_0_5 = OpConstant %f32 0.5
|
||||||
%f32_0_25 = OpConstant %f32 0.25
|
%f32_0_25 = OpConstant %f32 0.25
|
||||||
%f32_0_75 = OpConstant %f32 0.75
|
%f32_0_75 = OpConstant %f32 0.75
|
||||||
|
|
||||||
|
%f64_0 = OpConstant %f64 0
|
||||||
|
%f64_1 = OpConstant %f64 1
|
||||||
|
|
||||||
%s32_0 = OpConstant %s32 0
|
%s32_0 = OpConstant %s32 0
|
||||||
%s32_1 = OpConstant %s32 1
|
%s32_1 = OpConstant %s32 1
|
||||||
%s32_2 = OpConstant %s32 2
|
%s32_2 = OpConstant %s32 2
|
||||||
@ -175,16 +179,6 @@ OpCapability SparseResidency
|
|||||||
%uniform_image_s32_3d_0001 = OpVariable %ptr_image_s32_3d_0001 UniformConstant
|
%uniform_image_s32_3d_0001 = OpVariable %ptr_image_s32_3d_0001 UniformConstant
|
||||||
%type_sampled_image_s32_3d_0001 = OpTypeSampledImage %type_image_s32_3d_0001
|
%type_sampled_image_s32_3d_0001 = OpTypeSampledImage %type_image_s32_3d_0001
|
||||||
|
|
||||||
%type_image_void_2d_0001 = OpTypeImage %void 2D 0 0 0 1 Unknown
|
|
||||||
%ptr_image_void_2d_0001 = OpTypePointer UniformConstant %type_image_void_2d_0001
|
|
||||||
%uniform_image_void_2d_0001 = OpVariable %ptr_image_void_2d_0001 UniformConstant
|
|
||||||
%type_sampled_image_void_2d_0001 = OpTypeSampledImage %type_image_void_2d_0001
|
|
||||||
|
|
||||||
%type_image_void_2d_0002 = OpTypeImage %void 2D 0 0 0 2 Unknown
|
|
||||||
%ptr_image_void_2d_0002 = OpTypePointer UniformConstant %type_image_void_2d_0002
|
|
||||||
%uniform_image_void_2d_0002 = OpVariable %ptr_image_void_2d_0002 UniformConstant
|
|
||||||
%type_sampled_image_void_2d_0002 = OpTypeSampledImage %type_image_void_2d_0002
|
|
||||||
|
|
||||||
%type_image_f32_2d_0002 = OpTypeImage %f32 2D 0 0 0 2 Unknown
|
%type_image_f32_2d_0002 = OpTypeImage %f32 2D 0 0 0 2 Unknown
|
||||||
%ptr_image_f32_2d_0002 = OpTypePointer UniformConstant %type_image_f32_2d_0002
|
%ptr_image_f32_2d_0002 = OpTypePointer UniformConstant %type_image_f32_2d_0002
|
||||||
%uniform_image_f32_2d_0002 = OpVariable %ptr_image_f32_2d_0002 UniformConstant
|
%uniform_image_f32_2d_0002 = OpVariable %ptr_image_f32_2d_0002 UniformConstant
|
||||||
@ -210,15 +204,31 @@ OpCapability SparseResidency
|
|||||||
%uniform_image_f32_cube_0102_rgba32f = OpVariable %ptr_image_f32_cube_0102_rgba32f UniformConstant
|
%uniform_image_f32_cube_0102_rgba32f = OpVariable %ptr_image_f32_cube_0102_rgba32f UniformConstant
|
||||||
%type_sampled_image_f32_cube_0102_rgba32f = OpTypeSampledImage %type_image_f32_cube_0102_rgba32f
|
%type_sampled_image_f32_cube_0102_rgba32f = OpTypeSampledImage %type_image_f32_cube_0102_rgba32f
|
||||||
|
|
||||||
|
%type_sampler = OpTypeSampler
|
||||||
|
%ptr_sampler = OpTypePointer UniformConstant %type_sampler
|
||||||
|
%uniform_sampler = OpVariable %ptr_sampler UniformConstant
|
||||||
|
)";
|
||||||
|
|
||||||
|
if (env == SPV_ENV_UNIVERSAL_1_0) {
|
||||||
|
ss << R"(
|
||||||
|
%type_image_void_2d_0001 = OpTypeImage %void 2D 0 0 0 1 Unknown
|
||||||
|
%ptr_image_void_2d_0001 = OpTypePointer UniformConstant %type_image_void_2d_0001
|
||||||
|
%uniform_image_void_2d_0001 = OpVariable %ptr_image_void_2d_0001 UniformConstant
|
||||||
|
%type_sampled_image_void_2d_0001 = OpTypeSampledImage %type_image_void_2d_0001
|
||||||
|
|
||||||
|
%type_image_void_2d_0002 = OpTypeImage %void 2D 0 0 0 2 Unknown
|
||||||
|
%ptr_image_void_2d_0002 = OpTypePointer UniformConstant %type_image_void_2d_0002
|
||||||
|
%uniform_image_void_2d_0002 = OpVariable %ptr_image_void_2d_0002 UniformConstant
|
||||||
|
%type_sampled_image_void_2d_0002 = OpTypeSampledImage %type_image_void_2d_0002
|
||||||
|
|
||||||
%type_image_f32_rect_0001 = OpTypeImage %f32 Rect 0 0 0 1 Unknown
|
%type_image_f32_rect_0001 = OpTypeImage %f32 Rect 0 0 0 1 Unknown
|
||||||
%ptr_image_f32_rect_0001 = OpTypePointer UniformConstant %type_image_f32_rect_0001
|
%ptr_image_f32_rect_0001 = OpTypePointer UniformConstant %type_image_f32_rect_0001
|
||||||
%uniform_image_f32_rect_0001 = OpVariable %ptr_image_f32_rect_0001 UniformConstant
|
%uniform_image_f32_rect_0001 = OpVariable %ptr_image_f32_rect_0001 UniformConstant
|
||||||
%type_sampled_image_f32_rect_0001 = OpTypeSampledImage %type_image_f32_rect_0001
|
%type_sampled_image_f32_rect_0001 = OpTypeSampledImage %type_image_f32_rect_0001
|
||||||
|
)";
|
||||||
|
}
|
||||||
|
|
||||||
%type_sampler = OpTypeSampler
|
ss << R"(
|
||||||
%ptr_sampler = OpTypePointer UniformConstant %type_sampler
|
|
||||||
%uniform_sampler = OpVariable %ptr_sampler UniformConstant
|
|
||||||
|
|
||||||
%main = OpFunction %void None %func
|
%main = OpFunction %void None %func
|
||||||
%main_entry = OpLabel
|
%main_entry = OpLabel
|
||||||
)";
|
)";
|
||||||
@ -332,6 +342,7 @@ std::string GetShaderHeader(
|
|||||||
std::ostringstream ss;
|
std::ostringstream ss;
|
||||||
ss << R"(
|
ss << R"(
|
||||||
OpCapability Shader
|
OpCapability Shader
|
||||||
|
OpCapability Int64
|
||||||
)";
|
)";
|
||||||
|
|
||||||
ss << capabilities_and_extensions;
|
ss << capabilities_and_extensions;
|
||||||
@ -344,6 +355,7 @@ OpEntryPoint Fragment %main "main"
|
|||||||
%bool = OpTypeBool
|
%bool = OpTypeBool
|
||||||
%f32 = OpTypeFloat 32
|
%f32 = OpTypeFloat 32
|
||||||
%u32 = OpTypeInt 32 0
|
%u32 = OpTypeInt 32 0
|
||||||
|
%u64 = OpTypeInt 64 0
|
||||||
%s32 = OpTypeInt 32 1
|
%s32 = OpTypeInt 32 1
|
||||||
)";
|
)";
|
||||||
|
|
||||||
@ -363,6 +375,32 @@ TEST_F(ValidateImage, TypeImageWrongSampledType) {
|
|||||||
"type"));
|
"type"));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
TEST_F(ValidateImage, TypeImageVoidSampledTypeVulkan) {
|
||||||
|
const std::string code = GetShaderHeader() + R"(
|
||||||
|
%img_type = OpTypeImage %void 2D 0 0 0 1 Unknown
|
||||||
|
)";
|
||||||
|
|
||||||
|
const spv_target_env env = SPV_ENV_VULKAN_1_0;
|
||||||
|
CompileSuccessfully(code, env);
|
||||||
|
ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions(env));
|
||||||
|
EXPECT_THAT(getDiagnosticString(),
|
||||||
|
HasSubstr("TypeImage: expected Sampled Type to be a 32-bit int "
|
||||||
|
"or float scalar type for Vulkan environment"));
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(ValidateImage, TypeImageU64SampledTypeVulkan) {
|
||||||
|
const std::string code = GetShaderHeader() + R"(
|
||||||
|
%img_type = OpTypeImage %u64 2D 0 0 0 1 Unknown
|
||||||
|
)";
|
||||||
|
|
||||||
|
const spv_target_env env = SPV_ENV_VULKAN_1_0;
|
||||||
|
CompileSuccessfully(code, env);
|
||||||
|
ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions(env));
|
||||||
|
EXPECT_THAT(getDiagnosticString(),
|
||||||
|
HasSubstr("TypeImage: expected Sampled Type to be a 32-bit int "
|
||||||
|
"or float scalar type for Vulkan environment"));
|
||||||
|
}
|
||||||
|
|
||||||
TEST_F(ValidateImage, TypeImageWrongDepth) {
|
TEST_F(ValidateImage, TypeImageWrongDepth) {
|
||||||
const std::string code = GetShaderHeader() + R"(
|
const std::string code = GetShaderHeader() + R"(
|
||||||
%img_type = OpTypeImage %f32 2D 3 0 0 1 Unknown
|
%img_type = OpTypeImage %f32 2D 3 0 0 1 Unknown
|
||||||
@ -454,6 +492,18 @@ TEST_F(ValidateImage, SampledImageSuccess) {
|
|||||||
ASSERT_EQ(SPV_SUCCESS, ValidateInstructions());
|
ASSERT_EQ(SPV_SUCCESS, ValidateInstructions());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
TEST_F(ValidateImage, SampledImageVulkanSuccess) {
|
||||||
|
const std::string body = R"(
|
||||||
|
%img = OpLoad %type_image_f32_2d_0001 %uniform_image_f32_2d_0001
|
||||||
|
%sampler = OpLoad %type_sampler %uniform_sampler
|
||||||
|
%simg = OpSampledImage %type_sampled_image_f32_2d_0001 %img %sampler
|
||||||
|
)";
|
||||||
|
|
||||||
|
const spv_target_env env = SPV_ENV_VULKAN_1_0;
|
||||||
|
CompileSuccessfully(GenerateShaderCode(body, "", "Fragment", env), env);
|
||||||
|
ASSERT_EQ(SPV_SUCCESS, ValidateInstructions(env));
|
||||||
|
}
|
||||||
|
|
||||||
TEST_F(ValidateImage, SampledImageWrongResultType) {
|
TEST_F(ValidateImage, SampledImageWrongResultType) {
|
||||||
const std::string body = R"(
|
const std::string body = R"(
|
||||||
%img = OpLoad %type_image_f32_2d_0001 %uniform_image_f32_2d_0001
|
%img = OpLoad %type_image_f32_2d_0001 %uniform_image_f32_2d_0001
|
||||||
@ -498,6 +548,21 @@ TEST_F(ValidateImage, SampledImageImageNotForSampling) {
|
|||||||
"Expected Image 'Sampled' parameter to be 0 or 1: SampledImage"));
|
"Expected Image 'Sampled' parameter to be 0 or 1: SampledImage"));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
TEST_F(ValidateImage, SampledImageVulkanUnknownSampled) {
|
||||||
|
const std::string body = R"(
|
||||||
|
%img = OpLoad %type_image_u32_2d_0000 %uniform_image_u32_2d_0000
|
||||||
|
%sampler = OpLoad %type_sampler %uniform_sampler
|
||||||
|
%simg = OpSampledImage %type_sampled_image_u32_2d_0000 %img %sampler
|
||||||
|
)";
|
||||||
|
|
||||||
|
const spv_target_env env = SPV_ENV_VULKAN_1_0;
|
||||||
|
CompileSuccessfully(GenerateShaderCode(body, "", "Fragment", env), env);
|
||||||
|
ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions(env));
|
||||||
|
EXPECT_THAT(getDiagnosticString(),
|
||||||
|
HasSubstr("Expected Image 'Sampled' parameter to be 1 for Vulkan "
|
||||||
|
"environment: SampledImage"));
|
||||||
|
}
|
||||||
|
|
||||||
TEST_F(ValidateImage, SampledImageNotSampler) {
|
TEST_F(ValidateImage, SampledImageNotSampler) {
|
||||||
const std::string body = R"(
|
const std::string body = R"(
|
||||||
%img = OpLoad %type_image_f32_2d_0001 %uniform_image_f32_2d_0001
|
%img = OpLoad %type_image_f32_2d_0001 %uniform_image_f32_2d_0001
|
||||||
@ -1603,7 +1668,7 @@ TEST_F(ValidateImage, SampleDrefImplicitLodWrongDrefType) {
|
|||||||
%img = OpLoad %type_image_u32_2d_0001 %uniform_image_u32_2d_0001
|
%img = OpLoad %type_image_u32_2d_0001 %uniform_image_u32_2d_0001
|
||||||
%sampler = OpLoad %type_sampler %uniform_sampler
|
%sampler = OpLoad %type_sampler %uniform_sampler
|
||||||
%simg = OpSampledImage %type_sampled_image_u32_2d_0001 %img %sampler
|
%simg = OpSampledImage %type_sampled_image_u32_2d_0001 %img %sampler
|
||||||
%res1 = OpImageSampleDrefImplicitLod %u32 %simg %f32vec2_00 %f16_1
|
%res1 = OpImageSampleDrefImplicitLod %u32 %simg %f32vec2_00 %f64_1
|
||||||
)";
|
)";
|
||||||
|
|
||||||
CompileSuccessfully(GenerateShaderCode(body).c_str());
|
CompileSuccessfully(GenerateShaderCode(body).c_str());
|
||||||
|
Loading…
Reference in New Issue
Block a user