mirror of
https://github.com/izzy2lost/xenia-edge.git
synced 2026-07-06 00:20:26 -07:00
[Testing] More compute shader tests
This commit is contained in:
@@ -0,0 +1,458 @@
|
||||
/**
|
||||
******************************************************************************
|
||||
* Xenia : Xbox 360 Emulator Research Project *
|
||||
******************************************************************************
|
||||
* Copyright 2025 Ben Vanik. All rights reserved. *
|
||||
* Released under the BSD license - see LICENSE in the root for more details. *
|
||||
******************************************************************************
|
||||
*/
|
||||
|
||||
#include "third_party/catch/include/catch.hpp"
|
||||
#include "xenia/gpu/shaders/testing/util/compute_test_harness.h"
|
||||
#include "xenia/gpu/shaders/testing/util/spirv_cross_wrapper.h"
|
||||
#include "xenia/gpu/shaders/testing/util/vulkan_test_device.h"
|
||||
|
||||
#include <cstdint>
|
||||
|
||||
// Define BYTE for D3D12 headers
|
||||
#ifndef BYTE
|
||||
typedef uint8_t BYTE;
|
||||
#endif
|
||||
|
||||
// Include DXBC bytecode
|
||||
#define apply_gamma_table_cs apply_gamma_table_cs_dxbc
|
||||
#include "xenia/gpu/shaders/bytecode/d3d12_5_1/apply_gamma_table_cs.h"
|
||||
#undef apply_gamma_table_cs
|
||||
|
||||
#define apply_gamma_table_fxaa_luma_cs apply_gamma_table_fxaa_luma_cs_dxbc
|
||||
#include "xenia/gpu/shaders/bytecode/d3d12_5_1/apply_gamma_table_fxaa_luma_cs.h"
|
||||
#undef apply_gamma_table_fxaa_luma_cs
|
||||
|
||||
// Include SPIR-V bytecode
|
||||
#define apply_gamma_table_cs apply_gamma_table_cs_spirv
|
||||
#include "xenia/gpu/shaders/bytecode/vulkan_spirv/apply_gamma_table_cs.h"
|
||||
#undef apply_gamma_table_cs
|
||||
|
||||
#define apply_gamma_table_fxaa_luma_cs apply_gamma_table_fxaa_luma_cs_spirv
|
||||
#include "xenia/gpu/shaders/bytecode/vulkan_spirv/apply_gamma_table_fxaa_luma_cs.h"
|
||||
#undef apply_gamma_table_fxaa_luma_cs
|
||||
|
||||
using namespace xe::gpu::shaders::testing;
|
||||
|
||||
// Tests for the production apply_gamma_table compute shader
|
||||
// Simple lookup table based gamma correction
|
||||
|
||||
// Helper to convert half-float (FP16) to float
|
||||
static float Half2Float(uint16_t h) {
|
||||
uint32_t sign = (h & 0x8000) << 16;
|
||||
uint32_t exp = (h & 0x7C00) >> 10;
|
||||
uint32_t frac = (h & 0x03FF);
|
||||
|
||||
if (exp == 0) {
|
||||
if (frac == 0) return 0.0f; // Zero
|
||||
// Denormalized
|
||||
exp = 1;
|
||||
while ((frac & 0x0400) == 0) {
|
||||
frac <<= 1;
|
||||
exp--;
|
||||
}
|
||||
frac &= 0x03FF;
|
||||
} else if (exp == 31) {
|
||||
// Inf or NaN
|
||||
return (frac == 0) ? INFINITY : NAN;
|
||||
}
|
||||
|
||||
uint32_t f = sign | ((exp + 112) << 23) | (frac << 13);
|
||||
float result;
|
||||
std::memcpy(&result, &f, sizeof(float));
|
||||
return result;
|
||||
}
|
||||
|
||||
// Helper to pack RGB into R10G10B10A2 format (BGR order as per shader)
|
||||
// "blue in bits 0:9, green in 10:19, red in 20:29"
|
||||
static uint32_t PackR10G10B10A2_BGR(uint32_t r, uint32_t g, uint32_t b,
|
||||
uint32_t a = 0) {
|
||||
return (b & 0x3FF) | ((g & 0x3FF) << 10) | ((r & 0x3FF) << 20) |
|
||||
((a & 0x3) << 30);
|
||||
}
|
||||
|
||||
TEST_CASE("apply_gamma_table: DXBC-converted production shader",
|
||||
"[shader][apply_gamma_table][cross_backend][dxbc]") {
|
||||
VulkanTestDevice device;
|
||||
if (!device.Initialize()) {
|
||||
WARN("Vulkan not available, skipping test");
|
||||
return;
|
||||
}
|
||||
|
||||
// Load DXBC and convert to SPIR-V
|
||||
std::vector<uint8_t> dxbc_bytes(
|
||||
apply_gamma_table_cs_dxbc,
|
||||
apply_gamma_table_cs_dxbc + sizeof(apply_gamma_table_cs_dxbc));
|
||||
|
||||
std::vector<uint32_t> spirv = SPIRVCrossWrapper::DXBCToSPIRV(dxbc_bytes);
|
||||
|
||||
if (spirv.empty()) {
|
||||
FAIL("DXBC to SPIR-V conversion failed: "
|
||||
<< SPIRVCrossWrapper::GetLastError());
|
||||
}
|
||||
|
||||
// Use SPIRV reflection to detect descriptor bindings
|
||||
auto bindings = SPIRVCrossWrapper::ReflectDescriptorBindings(spirv);
|
||||
|
||||
uint32_t gamma_ramp_set = 0, gamma_ramp_binding = 0;
|
||||
uint32_t source_tex_set = 0, source_tex_binding = 0;
|
||||
uint32_t output_img_set = 0, output_img_binding = 0;
|
||||
|
||||
for (const auto& binding : bindings) {
|
||||
// Map resources based on name
|
||||
if (binding.name == "t0") { // gamma ramp
|
||||
gamma_ramp_set = binding.set;
|
||||
gamma_ramp_binding = binding.binding;
|
||||
} else if (binding.name == "t1") { // source texture
|
||||
source_tex_set = binding.set;
|
||||
source_tex_binding = binding.binding;
|
||||
} else if (binding.name == "u0") { // output image
|
||||
output_img_set = binding.set;
|
||||
output_img_binding = binding.binding;
|
||||
}
|
||||
}
|
||||
|
||||
ComputeTestHarness harness(&device, spirv);
|
||||
REQUIRE(harness.IsValid());
|
||||
|
||||
const uint32_t width = 4;
|
||||
const uint32_t height = 2;
|
||||
|
||||
struct PushConstants {
|
||||
uint32_t width;
|
||||
uint32_t height;
|
||||
} push_const = {width, height};
|
||||
harness.SetPushConstants(push_const);
|
||||
|
||||
// DXBC converter puts push constants into cb1_struct uniform buffer
|
||||
harness.SetUniformBuffer(0, push_const, 0);
|
||||
|
||||
// Create gamma lookup table (256 entries)
|
||||
// Format: R10G10B10A2 with BGR packing
|
||||
// For testing: create a simple power curve (gamma 2.2)
|
||||
std::vector<uint32_t> gamma_table(256);
|
||||
for (uint32_t i = 0; i < 256; ++i) {
|
||||
float normalized = float(i) / 255.0f;
|
||||
float corrected = std::pow(normalized, 1.0f / 2.2f); // Gamma correction
|
||||
uint32_t output_10bit = uint32_t(corrected * 1023.0f + 0.5f);
|
||||
|
||||
// Pack as BGR in R10G10B10A2
|
||||
gamma_table[i] =
|
||||
PackR10G10B10A2_BGR(output_10bit, output_10bit, output_10bit, 0);
|
||||
}
|
||||
|
||||
// Bind gamma table as texel buffer (R10G10B10A2 format)
|
||||
harness.SetTexelBuffer(gamma_ramp_binding, gamma_table,
|
||||
vk::Format::eA2B10G10R10UnormPack32, gamma_ramp_set);
|
||||
|
||||
// Create source texture with test values (8-bit)
|
||||
std::vector<float> source_tex(width * height * 4);
|
||||
uint8_t test_values[] = {0, 64, 128, 192, 32, 96, 160, 224};
|
||||
|
||||
for (uint32_t i = 0; i < width * height; ++i) {
|
||||
uint32_t idx = i * 4;
|
||||
source_tex[idx + 0] = float(test_values[i]) / 255.0f; // R
|
||||
source_tex[idx + 1] = float(test_values[i]) / 255.0f; // G
|
||||
source_tex[idx + 2] = float(test_values[i]) / 255.0f; // B
|
||||
source_tex[idx + 3] = 1.0f; // A
|
||||
}
|
||||
|
||||
harness.SetTexture2D(source_tex_binding, width, height,
|
||||
vk::Format::eR32G32B32A32Sfloat, source_tex,
|
||||
source_tex_set);
|
||||
|
||||
harness.AllocateOutputImage2D(output_img_binding, width, height,
|
||||
vk::Format::eR16G16B16A16Sfloat,
|
||||
output_img_set);
|
||||
|
||||
harness.Dispatch(1, 1, 1);
|
||||
|
||||
auto output =
|
||||
harness.ReadOutputImage2D<uint16_t>(output_img_binding, output_img_set);
|
||||
REQUIRE(output.size() == width * height * 4);
|
||||
|
||||
// Validate lookup table output
|
||||
for (uint32_t i = 0; i < width * height; ++i) {
|
||||
uint8_t input_val = test_values[i];
|
||||
|
||||
// Calculate expected output from gamma table
|
||||
uint32_t packed = gamma_table[input_val];
|
||||
uint32_t expected_r = (packed >> 20) & 0x3FF;
|
||||
uint32_t expected_g = (packed >> 10) & 0x3FF;
|
||||
uint32_t expected_b = (packed >> 0) & 0x3FF;
|
||||
|
||||
float expected_r_norm = float(expected_r) / 1023.0f;
|
||||
float expected_g_norm = float(expected_g) / 1023.0f;
|
||||
float expected_b_norm = float(expected_b) / 1023.0f;
|
||||
|
||||
// Read output RGB channels
|
||||
float actual_r = Half2Float(output[i * 4 + 0]);
|
||||
float actual_g = Half2Float(output[i * 4 + 1]);
|
||||
float actual_b = Half2Float(output[i * 4 + 2]);
|
||||
|
||||
REQUIRE(actual_r == Approx(expected_r_norm).margin(0.01f));
|
||||
REQUIRE(actual_g == Approx(expected_g_norm).margin(0.01f));
|
||||
REQUIRE(actual_b == Approx(expected_b_norm).margin(0.01f));
|
||||
}
|
||||
|
||||
// Verify alpha channel is 1.0 (not FXAA luma variant)
|
||||
for (uint32_t i = 0; i < width * height; ++i) {
|
||||
float alpha = Half2Float(output[i * 4 + 3]);
|
||||
REQUIRE(alpha == Approx(1.0f).margin(0.001f));
|
||||
}
|
||||
}
|
||||
|
||||
TEST_CASE("apply_gamma_table: Native SPIR-V production shader",
|
||||
"[shader][apply_gamma_table][cross_backend][spirv]") {
|
||||
VulkanTestDevice device;
|
||||
if (!device.Initialize()) {
|
||||
WARN("Vulkan not available, skipping test");
|
||||
return;
|
||||
}
|
||||
|
||||
std::vector<uint32_t> spirv(
|
||||
apply_gamma_table_cs_spirv,
|
||||
apply_gamma_table_cs_spirv +
|
||||
sizeof(apply_gamma_table_cs_spirv) / sizeof(uint32_t));
|
||||
|
||||
REQUIRE(SPIRVCrossWrapper::ValidateSPIRV(spirv));
|
||||
|
||||
ComputeTestHarness harness(&device, spirv);
|
||||
REQUIRE(harness.IsValid());
|
||||
|
||||
const uint32_t width = 4;
|
||||
const uint32_t height = 2;
|
||||
|
||||
struct PushConstants {
|
||||
uint32_t width;
|
||||
uint32_t height;
|
||||
} push_const = {width, height};
|
||||
harness.SetPushConstants(push_const);
|
||||
|
||||
// Create gamma lookup table with identity mapping
|
||||
std::vector<uint32_t> gamma_table(256);
|
||||
for (uint32_t i = 0; i < 256; ++i) {
|
||||
uint32_t output_10bit = (i * 1023) / 255; // Scale 8-bit to 10-bit
|
||||
gamma_table[i] =
|
||||
PackR10G10B10A2_BGR(output_10bit, output_10bit, output_10bit, 0);
|
||||
}
|
||||
|
||||
harness.SetTexelBuffer(0, gamma_table, vk::Format::eA2B10G10R10UnormPack32,
|
||||
0);
|
||||
|
||||
// Create source texture
|
||||
std::vector<float> source_tex(width * height * 4);
|
||||
uint8_t test_values[] = {0, 64, 128, 192, 32, 96, 160, 224};
|
||||
|
||||
for (uint32_t i = 0; i < width * height; ++i) {
|
||||
uint32_t idx = i * 4;
|
||||
source_tex[idx + 0] = float(test_values[i]) / 255.0f;
|
||||
source_tex[idx + 1] = float(test_values[i]) / 255.0f;
|
||||
source_tex[idx + 2] = float(test_values[i]) / 255.0f;
|
||||
source_tex[idx + 3] = 1.0f;
|
||||
}
|
||||
|
||||
harness.SetTexture2D(0, width, height, vk::Format::eR32G32B32A32Sfloat,
|
||||
source_tex, 1);
|
||||
|
||||
harness.AllocateOutputImage2D(0, width, height,
|
||||
vk::Format::eR16G16B16A16Sfloat, 2);
|
||||
|
||||
harness.Dispatch(1, 1, 1);
|
||||
|
||||
auto output = harness.ReadOutputImage2D<uint16_t>(0, 2);
|
||||
REQUIRE(output.size() == width * height * 4);
|
||||
|
||||
// Validate identity mapping
|
||||
for (uint32_t i = 0; i < width * height; ++i) {
|
||||
uint8_t input_val = test_values[i];
|
||||
float expected = float((input_val * 1023) / 255) / 1023.0f;
|
||||
|
||||
float actual_r = Half2Float(output[i * 4 + 0]);
|
||||
float actual_g = Half2Float(output[i * 4 + 1]);
|
||||
float actual_b = Half2Float(output[i * 4 + 2]);
|
||||
|
||||
REQUIRE(actual_r == Approx(expected).margin(0.01f));
|
||||
REQUIRE(actual_g == Approx(expected).margin(0.01f));
|
||||
REQUIRE(actual_b == Approx(expected).margin(0.01f));
|
||||
}
|
||||
|
||||
// Verify alpha channel
|
||||
for (uint32_t i = 0; i < width * height; ++i) {
|
||||
float alpha = Half2Float(output[i * 4 + 3]);
|
||||
REQUIRE(alpha == Approx(1.0f).margin(0.001f));
|
||||
}
|
||||
}
|
||||
|
||||
TEST_CASE("apply_gamma_table: FXAA luma variant",
|
||||
"[shader][apply_gamma_table][fxaa_luma]") {
|
||||
VulkanTestDevice device;
|
||||
if (!device.Initialize()) {
|
||||
WARN("Vulkan not available, skipping test");
|
||||
return;
|
||||
}
|
||||
|
||||
std::vector<uint32_t> spirv(
|
||||
apply_gamma_table_fxaa_luma_cs_spirv,
|
||||
apply_gamma_table_fxaa_luma_cs_spirv +
|
||||
sizeof(apply_gamma_table_fxaa_luma_cs_spirv) / sizeof(uint32_t));
|
||||
|
||||
REQUIRE(SPIRVCrossWrapper::ValidateSPIRV(spirv));
|
||||
|
||||
ComputeTestHarness harness(&device, spirv);
|
||||
REQUIRE(harness.IsValid());
|
||||
|
||||
const uint32_t width = 4;
|
||||
const uint32_t height = 2;
|
||||
|
||||
struct PushConstants {
|
||||
uint32_t width;
|
||||
uint32_t height;
|
||||
} push_const = {width, height};
|
||||
harness.SetPushConstants(push_const);
|
||||
|
||||
// Create identity gamma table
|
||||
std::vector<uint32_t> gamma_table(256);
|
||||
for (uint32_t i = 0; i < 256; ++i) {
|
||||
uint32_t output_10bit = (i * 1023) / 255;
|
||||
gamma_table[i] =
|
||||
PackR10G10B10A2_BGR(output_10bit, output_10bit, output_10bit, 0);
|
||||
}
|
||||
|
||||
harness.SetTexelBuffer(0, gamma_table, vk::Format::eA2B10G10R10UnormPack32,
|
||||
0);
|
||||
|
||||
// Create source with different RGB values to test luma
|
||||
std::vector<float> source_tex(width * height * 4);
|
||||
uint8_t test_values[][3] = {
|
||||
{128, 128, 128}, // Gray
|
||||
{255, 0, 0}, // Red
|
||||
{0, 255, 0}, // Green
|
||||
{0, 0, 255}, // Blue
|
||||
{128, 64, 32}, // Mixed
|
||||
{192, 128, 64}, // Mixed
|
||||
{64, 192, 128}, // Mixed
|
||||
{32, 96, 224}, // Mixed
|
||||
};
|
||||
|
||||
for (uint32_t i = 0; i < width * height; ++i) {
|
||||
uint32_t idx = i * 4;
|
||||
source_tex[idx + 0] = float(test_values[i][0]) / 255.0f;
|
||||
source_tex[idx + 1] = float(test_values[i][1]) / 255.0f;
|
||||
source_tex[idx + 2] = float(test_values[i][2]) / 255.0f;
|
||||
source_tex[idx + 3] = 1.0f;
|
||||
}
|
||||
|
||||
harness.SetTexture2D(0, width, height, vk::Format::eR32G32B32A32Sfloat,
|
||||
source_tex, 1);
|
||||
|
||||
harness.AllocateOutputImage2D(0, width, height,
|
||||
vk::Format::eR16G16B16A16Sfloat, 2);
|
||||
|
||||
harness.Dispatch(1, 1, 1);
|
||||
|
||||
auto output = harness.ReadOutputImage2D<uint16_t>(0, 2);
|
||||
REQUIRE(output.size() == width * height * 4);
|
||||
|
||||
// Validate RGB and luma
|
||||
for (uint32_t i = 0; i < width * height; ++i) {
|
||||
float expected_rgb[3];
|
||||
for (uint32_t c = 0; c < 3; ++c) {
|
||||
uint8_t input_val = test_values[i][c];
|
||||
float expected = float((input_val * 1023) / 255) / 1023.0f;
|
||||
expected_rgb[c] = expected;
|
||||
|
||||
float actual = Half2Float(output[i * 4 + c]);
|
||||
REQUIRE(actual == Approx(expected).margin(0.01f));
|
||||
}
|
||||
|
||||
// Verify alpha contains perceptual luma
|
||||
float expected_luma = expected_rgb[0] * 0.299f + expected_rgb[1] * 0.587f +
|
||||
expected_rgb[2] * 0.114f;
|
||||
float actual_luma = Half2Float(output[i * 4 + 3]);
|
||||
REQUIRE(actual_luma == Approx(expected_luma).margin(0.01f));
|
||||
}
|
||||
}
|
||||
|
||||
TEST_CASE("apply_gamma_table: Non-linear gamma curves",
|
||||
"[shader][apply_gamma_table][curves]") {
|
||||
VulkanTestDevice device;
|
||||
if (!device.Initialize()) {
|
||||
WARN("Vulkan not available, skipping test");
|
||||
return;
|
||||
}
|
||||
|
||||
std::vector<uint32_t> spirv(
|
||||
apply_gamma_table_cs_spirv,
|
||||
apply_gamma_table_cs_spirv +
|
||||
sizeof(apply_gamma_table_cs_spirv) / sizeof(uint32_t));
|
||||
|
||||
REQUIRE(SPIRVCrossWrapper::ValidateSPIRV(spirv));
|
||||
|
||||
ComputeTestHarness harness(&device, spirv);
|
||||
REQUIRE(harness.IsValid());
|
||||
|
||||
const uint32_t width = 8;
|
||||
const uint32_t height = 1;
|
||||
|
||||
struct PushConstants {
|
||||
uint32_t width;
|
||||
uint32_t height;
|
||||
} push_const = {width, height};
|
||||
harness.SetPushConstants(push_const);
|
||||
|
||||
// Create non-linear gamma table (inverted curve)
|
||||
std::vector<uint32_t> gamma_table(256);
|
||||
for (uint32_t i = 0; i < 256; ++i) {
|
||||
uint32_t inverted = 255 - i;
|
||||
uint32_t output_10bit = (inverted * 1023) / 255;
|
||||
gamma_table[i] =
|
||||
PackR10G10B10A2_BGR(output_10bit, output_10bit, output_10bit, 0);
|
||||
}
|
||||
|
||||
harness.SetTexelBuffer(0, gamma_table, vk::Format::eA2B10G10R10UnormPack32,
|
||||
0);
|
||||
|
||||
// Test various input values
|
||||
std::vector<float> source_tex(width * height * 4);
|
||||
uint8_t test_values[] = {0, 32, 64, 96, 128, 160, 192, 224};
|
||||
|
||||
for (uint32_t i = 0; i < width; ++i) {
|
||||
uint32_t idx = i * 4;
|
||||
source_tex[idx + 0] = float(test_values[i]) / 255.0f;
|
||||
source_tex[idx + 1] = float(test_values[i]) / 255.0f;
|
||||
source_tex[idx + 2] = float(test_values[i]) / 255.0f;
|
||||
source_tex[idx + 3] = 1.0f;
|
||||
}
|
||||
|
||||
harness.SetTexture2D(0, width, height, vk::Format::eR32G32B32A32Sfloat,
|
||||
source_tex, 1);
|
||||
|
||||
harness.AllocateOutputImage2D(0, width, height,
|
||||
vk::Format::eR16G16B16A16Sfloat, 2);
|
||||
|
||||
harness.Dispatch(1, 1, 1);
|
||||
|
||||
auto output = harness.ReadOutputImage2D<uint16_t>(0, 2);
|
||||
REQUIRE(output.size() == width * height * 4);
|
||||
|
||||
// Validate inverted curve
|
||||
for (uint32_t i = 0; i < width; ++i) {
|
||||
uint8_t input_val = test_values[i];
|
||||
uint8_t inverted = 255 - input_val;
|
||||
float expected = float((inverted * 1023) / 255) / 1023.0f;
|
||||
|
||||
float actual_r = Half2Float(output[i * 4 + 0]);
|
||||
float actual_g = Half2Float(output[i * 4 + 1]);
|
||||
float actual_b = Half2Float(output[i * 4 + 2]);
|
||||
|
||||
REQUIRE(actual_r == Approx(expected).margin(0.01f));
|
||||
REQUIRE(actual_g == Approx(expected).margin(0.01f));
|
||||
REQUIRE(actual_b == Approx(expected).margin(0.01f));
|
||||
}
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
@@ -391,6 +391,45 @@ void ComputeTestHarness::SetTexture2DRaw(uint32_t binding, uint32_t width,
|
||||
info.width = width;
|
||||
info.height = height;
|
||||
info.format = format;
|
||||
info.samples = vk::SampleCountFlagBits::e1;
|
||||
info.is_storage = false;
|
||||
images_[{set, binding}] = std::move(info);
|
||||
|
||||
UpdateDescriptorSets();
|
||||
}
|
||||
|
||||
void ComputeTestHarness::SetTexture2DMSRaw(uint32_t binding, uint32_t width,
|
||||
uint32_t height, vk::Format format,
|
||||
const void* data, size_t byte_size,
|
||||
vk::SampleCountFlagBits samples,
|
||||
uint32_t set) {
|
||||
// MSAA depth textures require depth format and rendering
|
||||
auto image =
|
||||
device_->CreateImage(width, height, format, vk::ImageTiling::eOptimal,
|
||||
vk::ImageUsageFlagBits::eSampled |
|
||||
vk::ImageUsageFlagBits::eDepthStencilAttachment,
|
||||
vk::MemoryPropertyFlagBits::eDeviceLocal, samples);
|
||||
|
||||
auto memory =
|
||||
device_->AllocateMemory(image, vk::MemoryPropertyFlagBits::eDeviceLocal);
|
||||
|
||||
auto view = device_->CreateImageView(
|
||||
image, format, vk::ImageAspectFlagBits::eDepth, samples);
|
||||
|
||||
// Render depth pattern using graphics pipeline
|
||||
device_->RenderDepthPattern(image, view, width, height, format, samples);
|
||||
|
||||
auto sampler = device_->CreateSampler();
|
||||
|
||||
ImageInfo info;
|
||||
info.image = std::move(image);
|
||||
info.memory = std::move(memory);
|
||||
info.view = std::move(view);
|
||||
info.sampler = std::move(sampler);
|
||||
info.width = width;
|
||||
info.height = height;
|
||||
info.format = format;
|
||||
info.samples = samples;
|
||||
info.is_storage = false;
|
||||
images_[{set, binding}] = std::move(info);
|
||||
|
||||
@@ -432,6 +471,7 @@ void ComputeTestHarness::AllocateOutputImage2D(uint32_t binding, uint32_t width,
|
||||
info.width = width;
|
||||
info.height = height;
|
||||
info.format = format;
|
||||
info.samples = vk::SampleCountFlagBits::e1;
|
||||
info.is_storage = true;
|
||||
images_[{set, binding}] = std::move(info);
|
||||
|
||||
|
||||
@@ -83,6 +83,15 @@ class ComputeTestHarness {
|
||||
data.size() * sizeof(T), set);
|
||||
}
|
||||
|
||||
// Set multisampled texture data (creates MSAA texture and uploads data)
|
||||
template <typename T>
|
||||
void SetTexture2DMS(uint32_t binding, uint32_t width, uint32_t height,
|
||||
vk::Format format, const std::vector<T>& data,
|
||||
vk::SampleCountFlagBits samples, uint32_t set = 0) {
|
||||
SetTexture2DMSRaw(binding, width, height, format, data.data(),
|
||||
data.size() * sizeof(T), samples, set);
|
||||
}
|
||||
|
||||
// Allocate output image (creates writable 2D image)
|
||||
void AllocateOutputImage2D(uint32_t binding, uint32_t width, uint32_t height,
|
||||
vk::Format format, uint32_t set = 0);
|
||||
@@ -147,6 +156,9 @@ class ComputeTestHarness {
|
||||
void SetTexture2DRaw(uint32_t binding, uint32_t width, uint32_t height,
|
||||
vk::Format format, const void* data, size_t byte_size,
|
||||
uint32_t set);
|
||||
void SetTexture2DMSRaw(uint32_t binding, uint32_t width, uint32_t height,
|
||||
vk::Format format, const void* data, size_t byte_size,
|
||||
vk::SampleCountFlagBits samples, uint32_t set);
|
||||
void SetPushConstantsRaw(const void* data, size_t byte_size);
|
||||
|
||||
bool CreateShaderModule(const std::vector<uint32_t>& spirv);
|
||||
@@ -174,6 +186,7 @@ class ComputeTestHarness {
|
||||
uint32_t width = 0;
|
||||
uint32_t height = 0;
|
||||
vk::Format format = vk::Format::eUndefined;
|
||||
vk::SampleCountFlagBits samples = vk::SampleCountFlagBits::e1;
|
||||
bool is_storage = false;
|
||||
};
|
||||
|
||||
|
||||
@@ -0,0 +1,7 @@
|
||||
#version 450
|
||||
|
||||
layout(location = 0) in float inDepth;
|
||||
|
||||
void main() {
|
||||
gl_FragDepth = inDepth;
|
||||
}
|
||||
@@ -0,0 +1,18 @@
|
||||
#version 450
|
||||
|
||||
layout(location = 0) out float outDepth;
|
||||
|
||||
void main() {
|
||||
// Fullscreen triangle
|
||||
vec2 positions[3] = vec2[](
|
||||
vec2(-1.0, -1.0),
|
||||
vec2(3.0, -1.0),
|
||||
vec2(-1.0, 3.0)
|
||||
);
|
||||
|
||||
gl_Position = vec4(positions[gl_VertexIndex], 0.0, 1.0);
|
||||
|
||||
// Varying depth based on position
|
||||
// Maps from [-1,3] range to [0,0.5] for X coordinate
|
||||
outDepth = (positions[gl_VertexIndex].x + 1.0) * 0.125;
|
||||
}
|
||||
Binary file not shown.
@@ -0,0 +1,81 @@
|
||||
#pragma once
|
||||
#include <cstdint>
|
||||
|
||||
// Auto-generated from depth_pattern_vert.spv
|
||||
static const uint32_t depth_pattern_vert_spv[] = {
|
||||
0x07230203, 0x00010000, 0x0008000b, 0x00000032, 0x00000000, 0x00020011,
|
||||
0x00000001, 0x0006000b, 0x00000001, 0x4c534c47, 0x6474732e, 0x3035342e,
|
||||
0x00000000, 0x0003000e, 0x00000000, 0x00000001, 0x0008000f, 0x00000000,
|
||||
0x00000004, 0x6e69616d, 0x00000000, 0x00000018, 0x0000001c, 0x00000029,
|
||||
0x00030003, 0x00000002, 0x000001c2, 0x00040005, 0x00000004, 0x6e69616d,
|
||||
0x00000000, 0x00050005, 0x0000000c, 0x69736f70, 0x6e6f6974, 0x00000073,
|
||||
0x00060005, 0x00000016, 0x505f6c67, 0x65567265, 0x78657472, 0x00000000,
|
||||
0x00060006, 0x00000016, 0x00000000, 0x505f6c67, 0x7469736f, 0x006e6f69,
|
||||
0x00070006, 0x00000016, 0x00000001, 0x505f6c67, 0x746e696f, 0x657a6953,
|
||||
0x00000000, 0x00070006, 0x00000016, 0x00000002, 0x435f6c67, 0x4470696c,
|
||||
0x61747369, 0x0065636e, 0x00070006, 0x00000016, 0x00000003, 0x435f6c67,
|
||||
0x446c6c75, 0x61747369, 0x0065636e, 0x00030005, 0x00000018, 0x00000000,
|
||||
0x00060005, 0x0000001c, 0x565f6c67, 0x65747265, 0x646e4978, 0x00007865,
|
||||
0x00050005, 0x00000029, 0x4474756f, 0x68747065, 0x00000000, 0x00030047,
|
||||
0x00000016, 0x00000002, 0x00050048, 0x00000016, 0x00000000, 0x0000000b,
|
||||
0x00000000, 0x00050048, 0x00000016, 0x00000001, 0x0000000b, 0x00000001,
|
||||
0x00050048, 0x00000016, 0x00000002, 0x0000000b, 0x00000003, 0x00050048,
|
||||
0x00000016, 0x00000003, 0x0000000b, 0x00000004, 0x00040047, 0x0000001c,
|
||||
0x0000000b, 0x0000002a, 0x00040047, 0x00000029, 0x0000001e, 0x00000000,
|
||||
0x00020013, 0x00000002, 0x00030021, 0x00000003, 0x00000002, 0x00030016,
|
||||
0x00000006, 0x00000020, 0x00040017, 0x00000007, 0x00000006, 0x00000002,
|
||||
0x00040015, 0x00000008, 0x00000020, 0x00000000, 0x0004002b, 0x00000008,
|
||||
0x00000009, 0x00000003, 0x0004001c, 0x0000000a, 0x00000007, 0x00000009,
|
||||
0x00040020, 0x0000000b, 0x00000007, 0x0000000a, 0x0004002b, 0x00000006,
|
||||
0x0000000d, 0xbf800000, 0x0005002c, 0x00000007, 0x0000000e, 0x0000000d,
|
||||
0x0000000d, 0x0004002b, 0x00000006, 0x0000000f, 0x40400000, 0x0005002c,
|
||||
0x00000007, 0x00000010, 0x0000000f, 0x0000000d, 0x0005002c, 0x00000007,
|
||||
0x00000011, 0x0000000d, 0x0000000f, 0x0006002c, 0x0000000a, 0x00000012,
|
||||
0x0000000e, 0x00000010, 0x00000011, 0x00040017, 0x00000013, 0x00000006,
|
||||
0x00000004, 0x0004002b, 0x00000008, 0x00000014, 0x00000001, 0x0004001c,
|
||||
0x00000015, 0x00000006, 0x00000014, 0x0006001e, 0x00000016, 0x00000013,
|
||||
0x00000006, 0x00000015, 0x00000015, 0x00040020, 0x00000017, 0x00000003,
|
||||
0x00000016, 0x0004003b, 0x00000017, 0x00000018, 0x00000003, 0x00040015,
|
||||
0x00000019, 0x00000020, 0x00000001, 0x0004002b, 0x00000019, 0x0000001a,
|
||||
0x00000000, 0x00040020, 0x0000001b, 0x00000001, 0x00000019, 0x0004003b,
|
||||
0x0000001b, 0x0000001c, 0x00000001, 0x00040020, 0x0000001e, 0x00000007,
|
||||
0x00000007, 0x0004002b, 0x00000006, 0x00000021, 0x00000000, 0x0004002b,
|
||||
0x00000006, 0x00000022, 0x3f800000, 0x00040020, 0x00000026, 0x00000003,
|
||||
0x00000013, 0x00040020, 0x00000028, 0x00000003, 0x00000006, 0x0004003b,
|
||||
0x00000028, 0x00000029, 0x00000003, 0x0004002b, 0x00000008, 0x0000002b,
|
||||
0x00000000, 0x00040020, 0x0000002c, 0x00000007, 0x00000006, 0x0004002b,
|
||||
0x00000006, 0x00000030, 0x3e000000, 0x00050036, 0x00000002, 0x00000004,
|
||||
0x00000000, 0x00000003, 0x000200f8, 0x00000005, 0x0004003b, 0x0000000b,
|
||||
0x0000000c, 0x00000007, 0x0003003e, 0x0000000c, 0x00000012, 0x0004003d,
|
||||
0x00000019, 0x0000001d, 0x0000001c, 0x00050041, 0x0000001e, 0x0000001f,
|
||||
0x0000000c, 0x0000001d, 0x0004003d, 0x00000007, 0x00000020, 0x0000001f,
|
||||
0x00050051, 0x00000006, 0x00000023, 0x00000020, 0x00000000, 0x00050051,
|
||||
0x00000006, 0x00000024, 0x00000020, 0x00000001, 0x00070050, 0x00000013,
|
||||
0x00000025, 0x00000023, 0x00000024, 0x00000021, 0x00000022, 0x00050041,
|
||||
0x00000026, 0x00000027, 0x00000018, 0x0000001a, 0x0003003e, 0x00000027,
|
||||
0x00000025, 0x0004003d, 0x00000019, 0x0000002a, 0x0000001c, 0x00060041,
|
||||
0x0000002c, 0x0000002d, 0x0000000c, 0x0000002a, 0x0000002b, 0x0004003d,
|
||||
0x00000006, 0x0000002e, 0x0000002d, 0x00050081, 0x00000006, 0x0000002f,
|
||||
0x0000002e, 0x00000022, 0x00050085, 0x00000006, 0x00000031, 0x0000002f,
|
||||
0x00000030, 0x0003003e, 0x00000029, 0x00000031, 0x000100fd, 0x00010038,
|
||||
};
|
||||
|
||||
// Auto-generated from depth_pattern_frag.spv
|
||||
static const uint32_t depth_pattern_frag_spv[] = {
|
||||
0x07230203, 0x00010000, 0x0008000b, 0x0000000c, 0x00000000, 0x00020011,
|
||||
0x00000001, 0x0006000b, 0x00000001, 0x4c534c47, 0x6474732e, 0x3035342e,
|
||||
0x00000000, 0x0003000e, 0x00000000, 0x00000001, 0x0007000f, 0x00000004,
|
||||
0x00000004, 0x6e69616d, 0x00000000, 0x00000008, 0x0000000a, 0x00030010,
|
||||
0x00000004, 0x00000007, 0x00030010, 0x00000004, 0x0000000c, 0x00030003,
|
||||
0x00000002, 0x000001c2, 0x00040005, 0x00000004, 0x6e69616d, 0x00000000,
|
||||
0x00060005, 0x00000008, 0x465f6c67, 0x44676172, 0x68747065, 0x00000000,
|
||||
0x00040005, 0x0000000a, 0x65446e69, 0x00687470, 0x00040047, 0x00000008,
|
||||
0x0000000b, 0x00000016, 0x00040047, 0x0000000a, 0x0000001e, 0x00000000,
|
||||
0x00020013, 0x00000002, 0x00030021, 0x00000003, 0x00000002, 0x00030016,
|
||||
0x00000006, 0x00000020, 0x00040020, 0x00000007, 0x00000003, 0x00000006,
|
||||
0x0004003b, 0x00000007, 0x00000008, 0x00000003, 0x00040020, 0x00000009,
|
||||
0x00000001, 0x00000006, 0x0004003b, 0x00000009, 0x0000000a, 0x00000001,
|
||||
0x00050036, 0x00000002, 0x00000004, 0x00000000, 0x00000003, 0x000200f8,
|
||||
0x00000005, 0x0004003d, 0x00000006, 0x0000000b, 0x0000000a, 0x0003003e,
|
||||
0x00000008, 0x0000000b, 0x000100fd, 0x00010038,
|
||||
};
|
||||
Binary file not shown.
@@ -11,6 +11,7 @@
|
||||
|
||||
#include <cstring>
|
||||
#include "xenia/base/logging.h"
|
||||
#include "xenia/gpu/shaders/testing/util/depth_pattern_shaders.h"
|
||||
|
||||
namespace xe {
|
||||
namespace gpu {
|
||||
@@ -170,12 +171,15 @@ void VulkanTestDevice::Unmap(const vk::raii::DeviceMemory& memory) {
|
||||
memory.unmapMemory();
|
||||
}
|
||||
|
||||
vk::raii::Image VulkanTestDevice::CreateImage(
|
||||
uint32_t width, uint32_t height, vk::Format format, vk::ImageTiling tiling,
|
||||
vk::ImageUsageFlags usage, vk::MemoryPropertyFlags mem_props) {
|
||||
vk::raii::Image VulkanTestDevice::CreateImage(uint32_t width, uint32_t height,
|
||||
vk::Format format,
|
||||
vk::ImageTiling tiling,
|
||||
vk::ImageUsageFlags usage,
|
||||
vk::MemoryPropertyFlags mem_props,
|
||||
vk::SampleCountFlagBits samples) {
|
||||
vk::ImageCreateInfo image_info({}, vk::ImageType::e2D, format,
|
||||
vk::Extent3D(width, height, 1), 1, 1,
|
||||
vk::SampleCountFlagBits::e1, tiling, usage);
|
||||
vk::Extent3D(width, height, 1), 1, 1, samples,
|
||||
tiling, usage);
|
||||
|
||||
return vk::raii::Image(*device_, image_info);
|
||||
}
|
||||
@@ -194,7 +198,9 @@ vk::raii::DeviceMemory VulkanTestDevice::AllocateMemory(
|
||||
|
||||
vk::raii::ImageView VulkanTestDevice::CreateImageView(
|
||||
const vk::raii::Image& image, vk::Format format,
|
||||
vk::ImageAspectFlags aspect_flags) {
|
||||
vk::ImageAspectFlags aspect_flags, vk::SampleCountFlagBits samples) {
|
||||
// MSAA textures always use e2D view type (samples are part of image, not
|
||||
// array layers)
|
||||
vk::ImageViewCreateInfo view_info(
|
||||
{}, *image, vk::ImageViewType::e2D, format, {},
|
||||
vk::ImageSubresourceRange(aspect_flags, 0, 1, 0, 1));
|
||||
@@ -342,6 +348,150 @@ void VulkanTestDevice::DownloadFromImage(const vk::raii::Image& image,
|
||||
DownloadFromBuffer(staging_buffer, staging_memory, data, size);
|
||||
}
|
||||
|
||||
vk::raii::ShaderModule VulkanTestDevice::CreateShaderModule(
|
||||
const std::vector<uint32_t>& spirv) {
|
||||
vk::ShaderModuleCreateInfo create_info({}, spirv.size() * sizeof(uint32_t),
|
||||
spirv.data());
|
||||
return vk::raii::ShaderModule(*device_, create_info);
|
||||
}
|
||||
|
||||
vk::raii::RenderPass VulkanTestDevice::CreateRenderPass(
|
||||
vk::Format depth_format, vk::SampleCountFlagBits samples) {
|
||||
vk::AttachmentDescription depth_attachment(
|
||||
{}, depth_format, samples, vk::AttachmentLoadOp::eClear,
|
||||
vk::AttachmentStoreOp::eStore, vk::AttachmentLoadOp::eDontCare,
|
||||
vk::AttachmentStoreOp::eDontCare, vk::ImageLayout::eUndefined,
|
||||
vk::ImageLayout::eDepthStencilAttachmentOptimal);
|
||||
|
||||
vk::AttachmentReference depth_ref(
|
||||
0, vk::ImageLayout::eDepthStencilAttachmentOptimal);
|
||||
|
||||
vk::SubpassDescription subpass;
|
||||
subpass.pipelineBindPoint = vk::PipelineBindPoint::eGraphics;
|
||||
subpass.pDepthStencilAttachment = &depth_ref;
|
||||
|
||||
vk::RenderPassCreateInfo create_info({}, depth_attachment, subpass);
|
||||
return vk::raii::RenderPass(*device_, create_info);
|
||||
}
|
||||
|
||||
vk::raii::Framebuffer VulkanTestDevice::CreateFramebuffer(
|
||||
const vk::raii::RenderPass& render_pass,
|
||||
const vk::raii::ImageView& depth_view, uint32_t width, uint32_t height) {
|
||||
vk::FramebufferCreateInfo create_info({}, *render_pass, *depth_view, width,
|
||||
height, 1);
|
||||
return vk::raii::Framebuffer(*device_, create_info);
|
||||
}
|
||||
|
||||
void VulkanTestDevice::RenderDepthPattern(const vk::raii::Image& depth_image,
|
||||
const vk::raii::ImageView& depth_view,
|
||||
uint32_t width, uint32_t height,
|
||||
vk::Format depth_format,
|
||||
vk::SampleCountFlagBits samples) {
|
||||
// Use precompiled GLSL shaders
|
||||
std::vector<uint32_t> vert_spirv(
|
||||
depth_pattern_vert_spv,
|
||||
depth_pattern_vert_spv +
|
||||
sizeof(depth_pattern_vert_spv) / sizeof(uint32_t));
|
||||
std::vector<uint32_t> frag_spirv(
|
||||
depth_pattern_frag_spv,
|
||||
depth_pattern_frag_spv +
|
||||
sizeof(depth_pattern_frag_spv) / sizeof(uint32_t));
|
||||
|
||||
auto vert_module = CreateShaderModule(vert_spirv);
|
||||
auto frag_module = CreateShaderModule(frag_spirv);
|
||||
|
||||
auto render_pass = CreateRenderPass(depth_format, samples);
|
||||
auto framebuffer = CreateFramebuffer(render_pass, depth_view, width, height);
|
||||
|
||||
// Create pipeline layout (no descriptors needed)
|
||||
vk::PipelineLayoutCreateInfo layout_info;
|
||||
auto pipeline_layout = vk::raii::PipelineLayout(*device_, layout_info);
|
||||
|
||||
// Shader stages
|
||||
vk::PipelineShaderStageCreateInfo vert_stage(
|
||||
{}, vk::ShaderStageFlagBits::eVertex, *vert_module, "main");
|
||||
vk::PipelineShaderStageCreateInfo frag_stage(
|
||||
{}, vk::ShaderStageFlagBits::eFragment, *frag_module, "main");
|
||||
std::vector<vk::PipelineShaderStageCreateInfo> stages = {vert_stage,
|
||||
frag_stage};
|
||||
|
||||
// Vertex input (none - generated in shader)
|
||||
vk::PipelineVertexInputStateCreateInfo vertex_input;
|
||||
|
||||
// Input assembly
|
||||
vk::PipelineInputAssemblyStateCreateInfo input_assembly(
|
||||
{}, vk::PrimitiveTopology::eTriangleList);
|
||||
|
||||
// Viewport
|
||||
vk::Viewport viewport(0, 0, static_cast<float>(width),
|
||||
static_cast<float>(height), 0.0f, 1.0f);
|
||||
vk::Rect2D scissor({0, 0}, {width, height});
|
||||
vk::PipelineViewportStateCreateInfo viewport_state({}, viewport, scissor);
|
||||
|
||||
// Rasterization
|
||||
vk::PipelineRasterizationStateCreateInfo rasterization(
|
||||
{}, false, false, vk::PolygonMode::eFill, vk::CullModeFlagBits::eNone,
|
||||
vk::FrontFace::eCounterClockwise, false, 0.0f, 0.0f, 0.0f, 1.0f);
|
||||
|
||||
// Multisample
|
||||
vk::PipelineMultisampleStateCreateInfo multisample({}, samples);
|
||||
|
||||
// Depth stencil
|
||||
vk::PipelineDepthStencilStateCreateInfo depth_stencil({}, true, true,
|
||||
vk::CompareOp::eAlways);
|
||||
|
||||
// Color blend (no color attachments)
|
||||
vk::PipelineColorBlendStateCreateInfo color_blend;
|
||||
|
||||
// Create pipeline
|
||||
vk::GraphicsPipelineCreateInfo pipeline_info(
|
||||
{}, stages, &vertex_input, &input_assembly, {}, &viewport_state,
|
||||
&rasterization, &multisample, &depth_stencil, &color_blend, {},
|
||||
*pipeline_layout, *render_pass);
|
||||
|
||||
auto pipeline = vk::raii::Pipeline(*device_, nullptr, pipeline_info);
|
||||
|
||||
// Render
|
||||
auto cmd = BeginSingleTimeCommands();
|
||||
|
||||
// Transition image to depth attachment
|
||||
vk::ImageMemoryBarrier barrier(
|
||||
{}, vk::AccessFlagBits::eDepthStencilAttachmentWrite,
|
||||
vk::ImageLayout::eUndefined,
|
||||
vk::ImageLayout::eDepthStencilAttachmentOptimal, VK_QUEUE_FAMILY_IGNORED,
|
||||
VK_QUEUE_FAMILY_IGNORED, *depth_image,
|
||||
vk::ImageSubresourceRange(vk::ImageAspectFlagBits::eDepth, 0, 1, 0, 1));
|
||||
|
||||
cmd.pipelineBarrier(vk::PipelineStageFlagBits::eTopOfPipe,
|
||||
vk::PipelineStageFlagBits::eEarlyFragmentTests, {}, {},
|
||||
{}, barrier);
|
||||
|
||||
// Begin render pass
|
||||
vk::ClearValue clear_value;
|
||||
clear_value.depthStencil.depth = 0.0f;
|
||||
clear_value.depthStencil.stencil = 0;
|
||||
vk::RenderPassBeginInfo render_pass_info(*render_pass, *framebuffer,
|
||||
vk::Rect2D({0, 0}, {width, height}),
|
||||
clear_value);
|
||||
|
||||
cmd.beginRenderPass(render_pass_info, vk::SubpassContents::eInline);
|
||||
cmd.bindPipeline(vk::PipelineBindPoint::eGraphics, *pipeline);
|
||||
cmd.draw(3, 1, 0, 0); // Draw fullscreen triangle
|
||||
cmd.endRenderPass();
|
||||
|
||||
// Transition to shader read
|
||||
barrier.srcAccessMask = vk::AccessFlagBits::eDepthStencilAttachmentWrite;
|
||||
barrier.dstAccessMask = vk::AccessFlagBits::eShaderRead;
|
||||
barrier.oldLayout = vk::ImageLayout::eDepthStencilAttachmentOptimal;
|
||||
barrier.newLayout = vk::ImageLayout::eShaderReadOnlyOptimal;
|
||||
|
||||
cmd.pipelineBarrier(vk::PipelineStageFlagBits::eLateFragmentTests,
|
||||
vk::PipelineStageFlagBits::eComputeShader, {}, {}, {},
|
||||
barrier);
|
||||
|
||||
EndSingleTimeCommands(cmd);
|
||||
}
|
||||
|
||||
} // namespace testing
|
||||
} // namespace shaders
|
||||
} // namespace gpu
|
||||
|
||||
@@ -46,20 +46,36 @@ class VulkanTestDevice {
|
||||
void Unmap(const vk::raii::DeviceMemory& memory);
|
||||
|
||||
// Image helpers
|
||||
vk::raii::Image CreateImage(uint32_t width, uint32_t height,
|
||||
vk::Format format, vk::ImageTiling tiling,
|
||||
vk::ImageUsageFlags usage,
|
||||
vk::MemoryPropertyFlags mem_props);
|
||||
vk::raii::Image CreateImage(
|
||||
uint32_t width, uint32_t height, vk::Format format,
|
||||
vk::ImageTiling tiling, vk::ImageUsageFlags usage,
|
||||
vk::MemoryPropertyFlags mem_props,
|
||||
vk::SampleCountFlagBits samples = vk::SampleCountFlagBits::e1);
|
||||
|
||||
vk::raii::DeviceMemory AllocateMemory(const vk::raii::Image& image,
|
||||
vk::MemoryPropertyFlags mem_props);
|
||||
|
||||
vk::raii::ImageView CreateImageView(const vk::raii::Image& image,
|
||||
vk::Format format,
|
||||
vk::ImageAspectFlags aspect_flags);
|
||||
vk::raii::ImageView CreateImageView(
|
||||
const vk::raii::Image& image, vk::Format format,
|
||||
vk::ImageAspectFlags aspect_flags,
|
||||
vk::SampleCountFlagBits samples = vk::SampleCountFlagBits::e1);
|
||||
|
||||
vk::raii::Sampler CreateSampler();
|
||||
|
||||
// Graphics pipeline helpers
|
||||
vk::raii::ShaderModule CreateShaderModule(const std::vector<uint32_t>& spirv);
|
||||
vk::raii::RenderPass CreateRenderPass(vk::Format depth_format,
|
||||
vk::SampleCountFlagBits samples);
|
||||
vk::raii::Framebuffer CreateFramebuffer(
|
||||
const vk::raii::RenderPass& render_pass,
|
||||
const vk::raii::ImageView& depth_view, uint32_t width, uint32_t height);
|
||||
|
||||
// Render a depth gradient pattern into an MSAA depth texture
|
||||
void RenderDepthPattern(const vk::raii::Image& depth_image,
|
||||
const vk::raii::ImageView& depth_view, uint32_t width,
|
||||
uint32_t height, vk::Format depth_format,
|
||||
vk::SampleCountFlagBits samples);
|
||||
|
||||
// Command buffer helpers
|
||||
vk::raii::CommandBuffer BeginSingleTimeCommands();
|
||||
void EndSingleTimeCommands(vk::raii::CommandBuffer& cmd);
|
||||
|
||||
Reference in New Issue
Block a user