// Testbench for MSL constexpr samplers. // It does not validate output, but it's useful for ad-hoc testing. #ifdef _MSC_VER #define _CRT_SECURE_NO_WARNINGS #endif #include #include #include #include #define SPVC_CHECKED_CALL(x) do { \ if ((x) != SPVC_SUCCESS) { \ fprintf(stderr, "Failed at line %d.\n", __LINE__); \ exit(1); \ } \ } while(0) #define SPVC_CHECKED_CALL_NEGATIVE(x) do { \ g_fail_on_error = SPVC_FALSE; \ if ((x) == SPVC_SUCCESS) { \ fprintf(stderr, "Failed at line %d.\n", __LINE__); \ exit(1); \ } \ g_fail_on_error = SPVC_TRUE; \ } while(0) static std::vector read_file(const char *path) { long len; FILE *file = fopen(path, "rb"); if (!file) return {}; fseek(file, 0, SEEK_END); len = ftell(file); rewind(file); std::vector buffer(len / sizeof(SpvId)); if (fread(buffer.data(), 1, len, file) != (size_t)len) { fclose(file); return {}; } fclose(file); return buffer; } int main(int argc, char **argv) { if (argc != 2) return EXIT_FAILURE; auto buffer = read_file(argv[1]); if (buffer.empty()) return EXIT_FAILURE; spvc_context ctx; spvc_parsed_ir parsed_ir; spvc_compiler compiler; SPVC_CHECKED_CALL(spvc_context_create(&ctx)); SPVC_CHECKED_CALL(spvc_context_parse_spirv(ctx, buffer.data(), buffer.size(), &parsed_ir)); SPVC_CHECKED_CALL(spvc_context_create_compiler(ctx, SPVC_BACKEND_MSL, parsed_ir, SPVC_CAPTURE_MODE_TAKE_OWNERSHIP, &compiler)); spvc_msl_resource_binding binding; spvc_msl_resource_binding_init(&binding); binding.desc_set = 1; binding.binding = 2; binding.stage = SpvExecutionModelFragment; binding.msl_texture = 0; binding.msl_sampler = 0; SPVC_CHECKED_CALL(spvc_compiler_msl_add_resource_binding(compiler, &binding)); binding.binding = 3; binding.msl_texture = 1; binding.msl_sampler = 1000; // Will be remapped anyways, sanity check. SPVC_CHECKED_CALL(spvc_compiler_msl_add_resource_binding(compiler, &binding)); binding.desc_set = 2; binding.binding = 2; binding.msl_texture = 2; SPVC_CHECKED_CALL(spvc_compiler_msl_add_resource_binding(compiler, &binding)); binding.binding = 3; binding.msl_texture = 3; SPVC_CHECKED_CALL(spvc_compiler_msl_add_resource_binding(compiler, &binding)); spvc_msl_constexpr_sampler samp; spvc_msl_constexpr_sampler_init(&samp); samp.s_address = SPVC_MSL_SAMPLER_ADDRESS_REPEAT; samp.t_address = SPVC_MSL_SAMPLER_ADDRESS_REPEAT; samp.r_address = SPVC_MSL_SAMPLER_ADDRESS_REPEAT; SPVC_CHECKED_CALL(spvc_compiler_msl_remap_constexpr_sampler_by_binding(compiler, 1, 3, &samp)); samp.s_address = SPVC_MSL_SAMPLER_ADDRESS_CLAMP_TO_EDGE; samp.t_address = SPVC_MSL_SAMPLER_ADDRESS_CLAMP_TO_EDGE; samp.r_address = SPVC_MSL_SAMPLER_ADDRESS_CLAMP_TO_EDGE; SPVC_CHECKED_CALL(spvc_compiler_msl_remap_constexpr_sampler_by_binding(compiler, 2, 4, &samp)); samp.compare_enable = SPVC_TRUE; samp.compare_func = SPVC_MSL_SAMPLER_COMPARE_FUNC_LESS; samp.s_address = SPVC_MSL_SAMPLER_ADDRESS_CLAMP_TO_EDGE; samp.t_address = SPVC_MSL_SAMPLER_ADDRESS_CLAMP_TO_EDGE; samp.r_address = SPVC_MSL_SAMPLER_ADDRESS_CLAMP_TO_EDGE; SPVC_CHECKED_CALL(spvc_compiler_msl_remap_constexpr_sampler_by_binding(compiler, 2, 5, &samp)); const char *str; SPVC_CHECKED_CALL(spvc_compiler_compile(compiler, &str)); // Should not be marked as used. if (spvc_compiler_msl_is_resource_used(compiler, SpvExecutionModelFragment, 2, 4)) return EXIT_FAILURE; // Should not be marked as used. if (spvc_compiler_msl_is_resource_used(compiler, SpvExecutionModelFragment, 2, 5)) return EXIT_FAILURE; // Should be marked, as a sanity check. if (!spvc_compiler_msl_is_resource_used(compiler, SpvExecutionModelFragment, 1, 2)) return EXIT_FAILURE; if (!spvc_compiler_msl_is_resource_used(compiler, SpvExecutionModelFragment, 1, 3)) return EXIT_FAILURE; if (!spvc_compiler_msl_is_resource_used(compiler, SpvExecutionModelFragment, 2, 2)) return EXIT_FAILURE; if (!spvc_compiler_msl_is_resource_used(compiler, SpvExecutionModelFragment, 2, 3)) return EXIT_FAILURE; fprintf(stderr, "Output:\n%s\n", str); }