Standalone Graphics Test (#4)

* Add graphics test [WIP]

* Ignore IDEA files

* Explicit cast from size_t to uint64_t

* Build statically when buiding examples

* Remove unused file

* Runs on ARM64 Linux

* Update .gitignore
This commit is contained in:
David Chavez 2024-05-15 02:35:45 +02:00 committed by GitHub
parent ecdd609c49
commit 21cfeae50c
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
15 changed files with 988 additions and 25 deletions

2
.gitignore vendored
View File

@ -21,3 +21,5 @@
*.pdb
build/
.vscode/
.idea
cmake-build-debug*

View File

@ -3,6 +3,11 @@ project(rt64)
set(CMAKE_CXX_STANDARD 17)
set(CMAKE_CXX_VISIBILITY_PRESET hidden)
option(RT64_BUILD_EXAMPLES "Build examples for RT64" OFF)
if (${RT64_BUILD_EXAMPLES})
set(RT64_STATIC ON)
endif()
function(preprocess INFILE OUTFILE OPTIONS)
if (CMAKE_CXX_COMPILER_FRONTEND_VARIANT STREQUAL "MSVC")
if (CMAKE_CXX_COMPILER_ID STREQUAL "Clang")
@ -29,7 +34,21 @@ if (WIN32)
configure_file("${PROJECT_SOURCE_DIR}/src/contrib/dxc/bin/x64/dxcompiler.dll" "dxcompiler.dll" COPYONLY)
configure_file("${PROJECT_SOURCE_DIR}/src/contrib/dxc/bin/x64/dxil.dll" "dxil.dll" COPYONLY)
else()
set (DXC "LD_LIBRARY_PATH=${PROJECT_SOURCE_DIR}/src/contrib/dxc/lib/x64" "${PROJECT_SOURCE_DIR}/src/contrib/dxc/bin/x64/dxc")
if (CMAKE_SYSTEM_PROCESSOR STREQUAL "x86_64")
if (APPLE)
set (DXC "DYLD_LIBRARY_PATH=${PROJECT_SOURCE_DIR}/src/contrib/dxc/lib/x64" "${PROJECT_SOURCE_DIR}/src/contrib/dxc/bin/x64/dxc")
else()
set (DXC "LD_LIBRARY_PATH=${PROJECT_SOURCE_DIR}/src/contrib/dxc/lib/x64" "${PROJECT_SOURCE_DIR}/src/contrib/dxc/bin/x64/dxc")
endif()
else()
if (APPLE)
set (DXC "DYLD_LIBRARY_PATH=${PROJECT_SOURCE_DIR}/src/contrib/dxc/lib/arm64" "${PROJECT_SOURCE_DIR}/src/contrib/dxc/bin/arm64/dxc-macos")
else()
set (DXC "LD_LIBRARY_PATH=${PROJECT_SOURCE_DIR}/src/contrib/dxc/lib/arm64" "${PROJECT_SOURCE_DIR}/src/contrib/dxc/bin/arm64/dxc-linux")
endif()
endif()
message(STATUS "DXC: ${DXC}")
endif()
# Build the file_to_c utility for converting binary files into a .c and .h file pair
@ -92,7 +111,7 @@ function(build_shader TARGETOBJ SHADERNAME OPTIONS)
cmake_path(GET OUTNAME PARENT_PATH OUTPUT_DIR)
file(MAKE_DIRECTORY ${OUTPUT_DIR})
# Compile DXIL shader binaries if building on Windows
if (${WIN32})
if (WIN32)
build_shader_dxil_impl(${TARGETOBJ} ${FILENAME} ${TARGET_NAME} ${OUTNAME} ${OPTIONS} ${EXTRA_ARGS})
endif()
build_shader_spirv_impl(${TARGETOBJ} ${FILENAME} ${TARGET_NAME} ${OUTNAME} ${OPTIONS} ${EXTRA_ARGS})
@ -155,13 +174,11 @@ function(build_geo_shader TARGETOBJ SHADERNAME)
endfunction()
function(build_ray_shader TARGETOBJ SHADERNAME)
if (NOT APPLE)
build_shader(${TARGETOBJ} ${SHADERNAME} "${DXC_RT_OPTS}" ${ARGN})
endif()
build_shader(${TARGETOBJ} ${SHADERNAME} "${DXC_RT_OPTS}" ${ARGN})
endfunction()
# Point cmake at src/contrib/mupen64plus-win32-deps/SDL2-2.26.3 for SDL2 on windows, look for an installed package on other systems
if (${WIN32})
if (WIN32)
set(SDL2_INCLUDE_DIRS "${PROJECT_SOURCE_DIR}/src/contrib/mupen64plus-win32-deps/SDL2-2.26.3/include")
set(SDL2_LIBRARIES "SDL2" "SDL2main")
link_directories("${PROJECT_SOURCE_DIR}/src/contrib/mupen64plus-win32-deps/SDL2-2.26.3/lib/x64")
@ -286,13 +303,17 @@ include_directories(
"${PROJECT_SOURCE_DIR}/src/contrib/D3D12MemoryAllocator/src"
"${PROJECT_SOURCE_DIR}/src/contrib/imgui"
"${PROJECT_SOURCE_DIR}/src/contrib/hlslpp/include"
"${PROJECT_SOURCE_DIR}/src/contrib/dxc/inc"
"${PROJECT_SOURCE_DIR}/src/contrib/Vulkan-Headers/include"
"${PROJECT_SOURCE_DIR}/src/contrib/VulkanMemoryAllocator/include"
"${PROJECT_SOURCE_DIR}/src/contrib/mupen64plus-core/src/api"
"${PROJECT_SOURCE_DIR}/src/contrib/nativefiledialog-extended/src/include"
)
if (WIN32)
# DXC only needs to be included during runtime for Windows.
include_directories("${PROJECT_SOURCE_DIR}/src/contrib/dxc/inc")
endif()
option(RT64_STATIC "Build RT64 as a static library" OFF)
if (${RT64_STATIC})
add_library(rt64 STATIC ${SOURCES})
@ -307,7 +328,7 @@ set_target_properties(rt64 PROPERTIES PREFIX "")
target_link_libraries(rt64 nfd)
# Add any Windows-specific source files and libraries
if (${WIN32})
if (WIN32)
target_sources(rt64 PRIVATE
"${PROJECT_SOURCE_DIR}/src/d3d12/rt64_d3d12.cpp"
"${PROJECT_SOURCE_DIR}/src/contrib/imgui/backends/imgui_impl_dx12.cpp"
@ -327,7 +348,7 @@ if (NOT ANDROID)
target_link_libraries(rt64 ${SDL2_LIBRARIES})
endif()
if (${CMAKE_SYSTEM_NAME} MATCHES "Linux")
if (CMAKE_SYSTEM_NAME MATCHES "Linux")
find_package(X11 REQUIRED)
target_include_directories(rt64 PUBLIC ${X11_INCLUDE_DIR})
target_link_libraries(rt64 ${X11_LIBRARIES})
@ -388,3 +409,17 @@ build_pixel_shader( rt64 "src/shaders/Im3DPS.hlsl")
build_pixel_shader( rt64 "src/shaders/PostProcessPS.hlsl")
target_include_directories(rt64 PRIVATE ${CMAKE_BINARY_DIR}/src)
if (RT64_BUILD_EXAMPLES)
add_executable(rhi_test "examples/rt64_render_interface.cpp" "examples/rhi_test.cpp")
target_link_libraries(rhi_test rt64)
build_pixel_shader( rhi_test "examples/shaders/RenderInterfaceTestPS.hlsl")
build_vertex_shader( rhi_test "examples/shaders/RenderInterfaceTestVS.hlsl")
build_compute_shader(rhi_test "examples/shaders/RenderInterfaceTestCS.hlsl")
build_ray_shader( rhi_test "examples/shaders/RenderInterfaceTestRT.hlsl")
build_pixel_shader( rhi_test "examples/shaders/RenderInterfaceTestPostPS.hlsl")
build_vertex_shader( rhi_test "examples/shaders/RenderInterfaceTestPostVS.hlsl")
target_include_directories(rhi_test PRIVATE ${CMAKE_BINARY_DIR}/examples)
endif()

View File

@ -1,4 +1,3 @@
#include <cassert>
#include "rhi/rt64_render_interface.h"
namespace RT64 {
@ -6,21 +5,16 @@ namespace RT64 {
extern std::unique_ptr<RenderInterface> CreateVulkanInterface();
}
int main() {
std::unique_ptr<RT64::RenderInterface> renderInterface;
int main(int argc, char** argv) {
std::unique_ptr<RT64::RenderInterface> renderInterface = RT64::CreateVulkanInterface();
// Create a render interface with the preferred backend.
#ifdef _WIN32
// Windows only: Can also use D3D12.
const bool useVulkan = true;
if (useVulkan) {
renderInterface = RT64::CreateVulkanInterface();
}
else {
#ifdef _WIN64
if (!useVulkan) {
renderInterface = RT64::CreateD3D12Interface();
#else
assert(false);
#endif
}
#endif
// Execute a blocking test that creates a window and draws some geometry to test the render interface.
RT64::RenderInterfaceTest(renderInterface.get());

View File

@ -0,0 +1,796 @@
//
// RT64
//
#include "rhi/rt64_render_interface.h"
#include <cassert>
#include <cstring>
#include <chrono>
#include <thread>
#ifdef _WIN64
#include "shaders/RenderInterfaceTestPS.hlsl.dxil.h"
#include "shaders/RenderInterfaceTestRT.hlsl.dxil.h"
#include "shaders/RenderInterfaceTestVS.hlsl.dxil.h"
#include "shaders/RenderInterfaceTestCS.hlsl.dxil.h"
#include "shaders/RenderInterfaceTestPostPS.hlsl.dxil.h"
#include "shaders/RenderInterfaceTestPostVS.hlsl.dxil.h"
#endif
#include "shaders/RenderInterfaceTestPS.hlsl.spirv.h"
#include "shaders/RenderInterfaceTestRT.hlsl.spirv.h"
#include "shaders/RenderInterfaceTestVS.hlsl.spirv.h"
#include "shaders/RenderInterfaceTestCS.hlsl.spirv.h"
#include "shaders/RenderInterfaceTestPostPS.hlsl.spirv.h"
#include "shaders/RenderInterfaceTestPostVS.hlsl.spirv.h"
#define ENABLE_SWAP_CHAIN 1
#define ENABLE_CLEAR 1
#define ENABLE_RASTER 1
#define ENABLE_TEXTURE 0
#define ENABLE_COMPUTE 0
#define ENABLE_RT 0
namespace RT64 {
struct RasterDescriptorSet : RenderDescriptorSetBase {
uint32_t gSampler;
uint32_t gTextures;
std::unique_ptr<RenderSampler> linearSampler;
RasterDescriptorSet(RenderDevice *device, uint32_t textureArraySize) {
linearSampler = device->createSampler(RenderSamplerDesc());
const uint32_t TextureArrayUpperRange = 512;
builder.begin();
gSampler = builder.addImmutableSampler(1, linearSampler.get());
gTextures = builder.addTexture(2, TextureArrayUpperRange);
builder.end(true, textureArraySize);
create(device);
}
};
struct ComputeDescriptorFirstSet : RenderDescriptorSetBase {
uint32_t gBlueNoiseTexture;
uint32_t gSampler;
uint32_t gTarget;
std::unique_ptr<RenderSampler> linearSampler;
ComputeDescriptorFirstSet(RenderDevice *device) {
linearSampler = device->createSampler(RenderSamplerDesc());
builder.begin();
gBlueNoiseTexture = builder.addTexture(1);
gSampler = builder.addImmutableSampler(2, linearSampler.get());
builder.end();
create(device);
}
};
struct ComputeDescriptorSecondSet : RenderDescriptorSetBase {
uint32_t gTarget;
ComputeDescriptorSecondSet(RenderDevice *device) {
builder.begin();
gTarget = builder.addReadWriteTexture(16);
builder.end();
create(device);
}
};
struct RaytracingDescriptorSet : RenderDescriptorSetBase {
uint32_t gBVH;
uint32_t gOutput;
uint32_t gBufferParams;
RaytracingDescriptorSet(RenderDevice *device) {
builder.begin();
gBVH = builder.addAccelerationStructure(0);
gOutput = builder.addReadWriteTexture(1);
gBufferParams = builder.addStructuredBuffer(2);
builder.end();
create(device);
}
};
struct TestMembers {
static const uint32_t BufferCount = 2;
static const uint32_t MSAACount = 4;
static const RenderFormat ColorFormat = RenderFormat::R8G8B8A8_UNORM;
static const RenderFormat DepthFormat = RenderFormat::D32_FLOAT;
#ifdef __ANDROID__
static const RenderFormat SwapchainFormat = RenderFormat::R8G8B8A8_UNORM;
#else
static const RenderFormat SwapchainFormat = RenderFormat::B8G8R8A8_UNORM;
#endif
const RenderInterface *renderInterface = nullptr;
std::unique_ptr<RenderDevice> device;
std::unique_ptr<RenderCommandQueue> commandQueue;
std::unique_ptr<RenderCommandList> commandList;
std::unique_ptr<RenderCommandFence> commandFence;
std::unique_ptr<RenderSwapChain> swapChain;
std::unique_ptr<RenderFramebuffer> framebuffer;
std::vector<std::unique_ptr<RenderFramebuffer>> swapFramebuffers;
std::unique_ptr<RenderSampler> linearSampler;
std::unique_ptr<RenderSampler> postSampler;
std::unique_ptr<RasterDescriptorSet> rasterSet;
std::unique_ptr<ComputeDescriptorFirstSet> computeFirstSet;
std::unique_ptr<ComputeDescriptorSecondSet> computeSecondSet;
std::unique_ptr<RaytracingDescriptorSet> rtSet;
std::unique_ptr<RenderDescriptorSet> postSet;
std::unique_ptr<RenderPipelineLayout> rasterPipelineLayout;
std::unique_ptr<RenderPipelineLayout> computePipelineLayout;
std::unique_ptr<RenderPipelineLayout> rtPipelineLayout;
std::unique_ptr<RenderPipelineLayout> postPipelineLayout;
std::unique_ptr<RenderPipeline> rasterPipeline;
std::unique_ptr<RenderPipeline> computePipeline;
std::unique_ptr<RenderPipeline> rtPipeline;
std::unique_ptr<RenderPipeline> postPipeline;
std::unique_ptr<RenderTexture> colorTargetMS;
std::unique_ptr<RenderTexture> colorTargetResolved;
std::unique_ptr<RenderTexture> depthTarget;
std::unique_ptr<RenderBuffer> uploadBuffer;
std::unique_ptr<RenderTexture> blueNoiseTexture;
std::unique_ptr<RenderBuffer> vertexBuffer;
std::unique_ptr<RenderBuffer> indexBuffer;
std::unique_ptr<RenderBuffer> rtParamsBuffer;
std::unique_ptr<RenderBuffer> rtVertexBuffer;
std::unique_ptr<RenderBuffer> rtScratchBuffer;
std::unique_ptr<RenderBuffer> rtInstancesBuffer;
std::unique_ptr<RenderBuffer> rtBottomLevelASBuffer;
std::unique_ptr<RenderAccelerationStructure> rtBottomLevelAS;
std::unique_ptr<RenderBuffer> rtTopLevelASBuffer;
std::unique_ptr<RenderAccelerationStructure> rtTopLevelAS;
std::unique_ptr<RenderBuffer> rtShaderBindingTableBuffer;
RenderShaderBindingTableInfo rtShaderBindingTableInfo;
RenderVertexBufferView vertexBufferView;
RenderIndexBufferView indexBufferView;
RenderInputSlot inputSlot;
} Test;
struct RasterPushConstant {
float colorAdd[4] = {};
uint32_t textureIndex = 0;
};
struct ComputePushConstant {
float Multiply[4] = {};
uint32_t Resolution[2] = {};
};
void TestInitialize(RenderInterface *renderInterface, RenderWindow window) {
Test.renderInterface = renderInterface;
Test.device = renderInterface->createDevice();
Test.commandQueue = Test.device->createCommandQueue(RenderCommandListType::DIRECT);
Test.commandList = Test.device->createCommandList(RenderCommandListType::DIRECT);
Test.commandFence = Test.device->createCommandFence();
# if ENABLE_SWAP_CHAIN
Test.swapChain = Test.commandQueue->createSwapChain(window, Test.BufferCount, Test.SwapchainFormat);
# endif
# if ENABLE_RASTER
const uint32_t textureArraySize = 3;
Test.rasterSet = std::make_unique<RasterDescriptorSet>(Test.device.get(), 3);
RenderPipelineLayoutBuilder layoutBuilder;
layoutBuilder.begin(false, true);
layoutBuilder.addPushConstant(0, 0, sizeof(RasterPushConstant), RenderShaderStageFlag::PIXEL);
layoutBuilder.addDescriptorSet(Test.rasterSet->builder);
layoutBuilder.end();
Test.rasterPipelineLayout = layoutBuilder.create(Test.device.get());
// Pick shader format depending on the render interface's requirements.
const RenderInterfaceCapabilities &interfaceCapabilities = Test.renderInterface->getCapabilities();
const RenderShaderFormat shaderFormat = interfaceCapabilities.shaderFormat;
const void *PSBlob = nullptr;
const void *VSBlob = nullptr;
const void *CSBlob = nullptr;
const void *RTBlob = nullptr;
const void *PostPSBlob = nullptr;
const void *PostVSBlob = nullptr;
uint64_t PSBlobSize = 0;
uint64_t VSBlobSize = 0;
uint64_t CSBlobSize = 0;
uint64_t RTBlobSize = 0;
uint64_t PostPSBlobSize = 0;
uint64_t PostVSBlobSize = 0;
switch (shaderFormat) {
#ifdef _WIN64
case RenderShaderFormat::DXIL:
PSBlob = RenderInterfaceTestPSBlobDXIL;
PSBlobSize = sizeof(RenderInterfaceTestPSBlobDXIL);
VSBlob = RenderInterfaceTestVSBlobDXIL;
VSBlobSize = sizeof(RenderInterfaceTestVSBlobDXIL);
CSBlob = RenderInterfaceTestCSBlobDXIL;
CSBlobSize = sizeof(RenderInterfaceTestCSBlobDXIL);
RTBlob = RenderInterfaceTestRTBlobDXIL;
RTBlobSize = sizeof(RenderInterfaceTestRTBlobDXIL);
PostPSBlob = RenderInterfaceTestPostPSBlobDXIL;
PostPSBlobSize = sizeof(RenderInterfaceTestPostPSBlobDXIL);
PostVSBlob = RenderInterfaceTestPostVSBlobDXIL;
PostVSBlobSize = sizeof(RenderInterfaceTestPostVSBlobDXIL);
break;
#endif
case RenderShaderFormat::SPIRV:
PSBlob = RenderInterfaceTestPSBlobSPIRV;
PSBlobSize = sizeof(RenderInterfaceTestPSBlobSPIRV);
VSBlob = RenderInterfaceTestVSBlobSPIRV;
VSBlobSize = sizeof(RenderInterfaceTestVSBlobSPIRV);
CSBlob = RenderInterfaceTestCSBlobSPIRV;
CSBlobSize = sizeof(RenderInterfaceTestCSBlobSPIRV);
RTBlob = RenderInterfaceTestRTBlobSPIRV;
RTBlobSize = sizeof(RenderInterfaceTestRTBlobSPIRV);
PostPSBlob = RenderInterfaceTestPostPSBlobSPIRV;
PostPSBlobSize = sizeof(RenderInterfaceTestPostPSBlobSPIRV);
PostVSBlob = RenderInterfaceTestPostVSBlobSPIRV;
PostVSBlobSize = sizeof(RenderInterfaceTestPostVSBlobSPIRV);
break;
default:
assert(false && "Unknown shader format.");
break;
}
const uint32_t VertexCount = 3;
const uint32_t FloatsPerVertex = 4;
const float Vertices[VertexCount * FloatsPerVertex] = {
-0.5f, -0.25f, 0.0f, 0.0f,
0.5f, -0.25f, 1.0f, 0.0f,
0.25f, 0.25f, 0.0f, 1.0f
};
const uint32_t Indices[3] = {
0, 1, 2
};
Test.inputSlot = RenderInputSlot(0, sizeof(float) * FloatsPerVertex);
std::vector<RenderInputElement> inputElements;
inputElements.emplace_back(RenderInputElement("POSITION", 0, 0, RenderFormat::R32G32_FLOAT, 0, 0));
inputElements.emplace_back(RenderInputElement("TEXCOORD", 0, 1, RenderFormat::R32G32_FLOAT, 0, sizeof(float) * 2));
std::unique_ptr<RenderShader> pixelShader = Test.device->createShader(PSBlob, PSBlobSize, "PSMain", shaderFormat);
std::unique_ptr<RenderShader> vertexShader = Test.device->createShader(VSBlob, VSBlobSize, "VSMain", shaderFormat);
RenderGraphicsPipelineDesc graphicsDesc;
graphicsDesc.inputSlots = &Test.inputSlot;
graphicsDesc.inputSlotsCount = 1;
graphicsDesc.inputElements = inputElements.data();
graphicsDesc.inputElementsCount = uint32_t(inputElements.size());
graphicsDesc.pipelineLayout = Test.rasterPipelineLayout.get();
graphicsDesc.pixelShader = pixelShader.get();
graphicsDesc.vertexShader = vertexShader.get();
graphicsDesc.renderTargetFormat[0] = Test.ColorFormat;
graphicsDesc.renderTargetBlend[0] = RenderBlendDesc::Copy();
graphicsDesc.depthTargetFormat = Test.DepthFormat;
graphicsDesc.renderTargetCount = 1;
graphicsDesc.multisampling.sampleCount = Test.MSAACount;
Test.rasterPipeline = Test.device->createGraphicsPipeline(graphicsDesc);
Test.postSampler = Test.device->createSampler(RenderSamplerDesc());
const RenderSampler *postSamplerPtr = Test.postSampler.get();
// Create the post processing pipeline
std::vector<RenderDescriptorRange> postDescriptorRanges = {
RenderDescriptorRange(RenderDescriptorRangeType::TEXTURE, 1, 1),
RenderDescriptorRange(RenderDescriptorRangeType::SAMPLER, 2, 1, &postSamplerPtr)
};
RenderDescriptorSetDesc postDescriptorSetDesc(postDescriptorRanges.data(), uint32_t(postDescriptorRanges.size()));
Test.postSet = Test.device->createDescriptorSet(postDescriptorSetDesc);
Test.postPipelineLayout = Test.device->createPipelineLayout(RenderPipelineLayoutDesc(nullptr, 0, &postDescriptorSetDesc, 1, false, true));
inputElements.clear();
inputElements.emplace_back(RenderInputElement("POSITION", 0, 0, RenderFormat::R32G32_FLOAT, 0, 0));
std::unique_ptr<RenderShader> postPixelShader = Test.device->createShader(PostPSBlob, PostPSBlobSize, "PSMain", shaderFormat);
std::unique_ptr<RenderShader> postVertexShader = Test.device->createShader(PostVSBlob, PostVSBlobSize, "VSMain", shaderFormat);
RenderGraphicsPipelineDesc postDesc;
postDesc.inputSlots = nullptr;
postDesc.inputSlotsCount = 0;
postDesc.inputElements = nullptr;
postDesc.inputElementsCount = 0;
postDesc.pipelineLayout = Test.postPipelineLayout.get();
postDesc.pixelShader = postPixelShader.get();
postDesc.vertexShader = postVertexShader.get();
postDesc.renderTargetFormat[0] = Test.SwapchainFormat;
postDesc.renderTargetBlend[0] = RenderBlendDesc::Copy();
postDesc.renderTargetCount = 1;
Test.postPipeline = Test.device->createGraphicsPipeline(postDesc);
# if ENABLE_TEXTURE
// Upload a texture.
const uint32_t Width = 512;
const uint32_t Height = 512;
const uint32_t RowLength = Width;
const RenderFormat Format = RenderFormat::R8G8B8A8_UNORM;
const uint32_t BufferSize = RowLength * Height * RenderFormatSize(Format);
Test.uploadBuffer = Test.device->createBuffer(RenderBufferDesc::UploadBuffer(BufferSize));
Test.blueNoiseTexture = Test.device->createTexture(RenderTextureDesc::Texture2D(Width, Height, 1, Format));
Test.rasterSet->setTexture(Test.rasterSet->gTextures + 2, Test.blueNoiseTexture.get(), RenderTextureLayout::SHADER_READ);
// Copy to upload buffer.
void *bufferData = Test.uploadBuffer->map();
memcpy(bufferData, LDR_64_64_64_RGB1_BGRA8, BufferSize);
Test.uploadBuffer->unmap();
// Run command list to copy the upload buffer to the texture.
Test.commandList->begin();
Test.commandList->barriers(RenderBarrierStage::COPY,
RenderBufferBarrier(Test.uploadBuffer.get(), RenderBufferAccess::READ),
RenderTextureBarrier(Test.blueNoiseTexture.get(), RenderTextureLayout::COPY_DEST)
);
Test.commandList->copyTextureRegion(
RenderTextureCopyLocation::Subresource(Test.blueNoiseTexture.get()),
RenderTextureCopyLocation::PlacedFootprint(Test.uploadBuffer.get(), Format, Width, Height, 1, RowLength));
Test.commandList->barriers(RenderBarrierStage::GRAPHICS_AND_COMPUTE, RenderTextureBarrier(Test.blueNoiseTexture.get(), RenderTextureLayout::SHADER_READ));
Test.commandList->end();
Test.commandQueue->executeCommandLists(Test.commandList.get(), Test.commandFence.get());
Test.commandQueue->waitForCommandFence(Test.commandFence.get());
# endif
Test.vertexBuffer = Test.device->createBuffer(RenderBufferDesc::VertexBuffer(sizeof(Vertices), RenderHeapType::UPLOAD));
void *dstData = Test.vertexBuffer->map();
memcpy(dstData, Vertices, sizeof(Vertices));
Test.vertexBuffer->unmap();
Test.vertexBufferView = RenderVertexBufferView(Test.vertexBuffer.get(), sizeof(Vertices));
Test.indexBuffer = Test.device->createBuffer(RenderBufferDesc::IndexBuffer(sizeof(Indices), RenderHeapType::UPLOAD));
dstData = Test.indexBuffer->map();
memcpy(dstData, Indices, sizeof(Indices));
Test.indexBuffer->unmap();
Test.indexBufferView = RenderIndexBufferView(Test.indexBuffer.get(), sizeof(Indices), RenderFormat::R32_UINT);
# endif
# if ENABLE_COMPUTE
Test.computeFirstSet = std::make_unique<ComputeDescriptorFirstSet>(Test.device.get());
Test.computeSecondSet = std::make_unique<ComputeDescriptorSecondSet>(Test.device.get());
Test.computeFirstSet->setTexture(Test.computeFirstSet->gBlueNoiseTexture, Test.blueNoiseTexture.get(), RenderTextureLayout::SHADER_READ);
layoutBuilder.begin();
layoutBuilder.addPushConstant(0, 0, sizeof(ComputePushConstant), RenderShaderStageFlag::COMPUTE);
layoutBuilder.addDescriptorSet(Test.computeFirstSet->builder);
layoutBuilder.addDescriptorSet(Test.computeSecondSet->builder);
layoutBuilder.end();
Test.computePipelineLayout = layoutBuilder.create(Test.device.get());
std::unique_ptr<RenderShader> computeShader = Test.device->createShader(CSBlob, CSBlobSize, "CSMain", shaderFormat);
RenderComputePipelineDesc computeDesc;
computeDesc.computeShader = computeShader.get();
computeDesc.pipelineLayout = Test.computePipelineLayout.get();
Test.computePipeline = Test.device->createComputePipeline(computeDesc);
# endif
# if ENABLE_RT
Test.rtSet = std::make_unique<RaytracingDescriptorSet>(Test.device.get());
layoutBuilder.begin(true);
layoutBuilder.addDescriptorSet(Test.rtSet->builder);
layoutBuilder.end();
Test.rtPipelineLayout = layoutBuilder.create(Test.device.get());
struct BufferParams {
float rgbMultiplier[3];
uint32_t pad[3];
};
BufferParams paramsToUpload[2];
paramsToUpload[0].rgbMultiplier[0] = 1.0f;
paramsToUpload[0].rgbMultiplier[1] = 0.25f;
paramsToUpload[0].rgbMultiplier[2] = 0.25f;
paramsToUpload[1].rgbMultiplier[0] = 0.25f;
paramsToUpload[1].rgbMultiplier[1] = 1.0f;
paramsToUpload[1].rgbMultiplier[2] = 0.25f;
RenderBufferStructuredView paramsView(sizeof(BufferParams));
Test.rtParamsBuffer = Test.device->createBuffer(RenderBufferDesc::UploadBuffer(sizeof(paramsToUpload), RenderBufferFlag::STORAGE));
Test.rtSet->setBuffer(Test.rtSet->gBufferParams, Test.rtParamsBuffer.get(), sizeof(paramsToUpload), &paramsView);
dstData = Test.rtParamsBuffer->map();
memcpy(dstData, paramsToUpload, sizeof(paramsToUpload));
Test.rtParamsBuffer->unmap();
RenderRaytracingPipelineLibrarySymbol rtLibrarySymbols[] = {
RenderRaytracingPipelineLibrarySymbol("ColorRayGen", RenderRaytracingPipelineLibrarySymbolType::RAYGEN),
RenderRaytracingPipelineLibrarySymbol("ColorClosestHit", RenderRaytracingPipelineLibrarySymbolType::CLOSEST_HIT),
RenderRaytracingPipelineLibrarySymbol("ColorMiss", RenderRaytracingPipelineLibrarySymbolType::MISS)
};
std::unique_ptr<RenderShader> rtShader = Test.device->createShader(RTBlob, RTBlobSize, nullptr, shaderFormat);
RenderRaytracingPipelineLibrary rtLibrary(rtShader.get(), rtLibrarySymbols, uint32_t(std::size(rtLibrarySymbols)));
RenderRaytracingPipelineHitGroup rtHitGroup("ColorHitGroup", "ColorClosestHit");
RenderRaytracingPipelineDesc rtPsoDesc;
rtPsoDesc.libraries = &rtLibrary;
rtPsoDesc.librariesCount = 1;
rtPsoDesc.hitGroups = &rtHitGroup;
rtPsoDesc.hitGroupsCount = 1;
rtPsoDesc.pipelineLayout = Test.rtPipelineLayout.get();
rtPsoDesc.maxPayloadSize = sizeof(float) * 4;
Test.rtPipeline = Test.device->createRaytracingPipeline(rtPsoDesc);
// Create RT BVH.
const float BLASVertices[] = {
0.25f, 0.25f, 1.0f,
0.75f, 0.25f, 1.0f,
0.5f, 0.75f, 1.0f
};
dstData = Test.uploadBuffer->map();
memcpy(dstData, BLASVertices, sizeof(BLASVertices));
Test.uploadBuffer->unmap();
Test.rtVertexBuffer = Test.device->createBuffer(RenderBufferDesc::VertexBuffer(sizeof(BLASVertices), RenderHeapType::DEFAULT, RenderBufferFlag::ACCELERATION_STRUCTURE_INPUT));
RenderBottomLevelASMesh blasMesh;
blasMesh.vertexBuffer = Test.rtVertexBuffer.get();
blasMesh.vertexFormat = RenderFormat::R32G32B32_FLOAT;
blasMesh.vertexCount = 3;
blasMesh.vertexStride = sizeof(float) * 3;
blasMesh.isOpaque = true;
RenderBottomLevelASBuildInfo blasBuildInfo;
Test.device->setBottomLevelASBuildInfo(blasBuildInfo, &blasMesh, 1);
Test.rtBottomLevelASBuffer = Test.device->createBuffer(RenderBufferDesc::AccelerationStructureBuffer(blasBuildInfo.accelerationStructureSize));
Test.rtBottomLevelAS = Test.device->createAccelerationStructure(RenderAccelerationStructureDesc(RenderAccelerationStructureType::BOTTOM_LEVEL, Test.rtBottomLevelASBuffer.get(), blasBuildInfo.accelerationStructureSize));
RenderTopLevelASInstance tlasInstance;
tlasInstance.bottomLevelAS = Test.rtBottomLevelASBuffer.get();
tlasInstance.instanceMask = 0xFF;
tlasInstance.cullDisable = true;
RenderTopLevelASBuildInfo tlasBuildInfo;
Test.device->setTopLevelASBuildInfo(tlasBuildInfo, &tlasInstance, 1);
Test.rtInstancesBuffer = Test.device->createBuffer(RenderBufferDesc::UploadBuffer(tlasBuildInfo.instancesBufferData.size(), RenderBufferFlag::ACCELERATION_STRUCTURE_INPUT));
dstData = Test.rtInstancesBuffer->map();
memcpy(dstData, tlasBuildInfo.instancesBufferData.data(), tlasBuildInfo.instancesBufferData.size());
Test.rtInstancesBuffer->unmap();
Test.rtScratchBuffer = Test.device->createBuffer(RenderBufferDesc::DefaultBuffer(std::max(blasBuildInfo.scratchSize, tlasBuildInfo.scratchSize), RenderBufferFlag::ACCELERATION_STRUCTURE_SCRATCH));
Test.rtTopLevelASBuffer = Test.device->createBuffer(RenderBufferDesc::AccelerationStructureBuffer(tlasBuildInfo.accelerationStructureSize));
Test.rtTopLevelAS = Test.device->createAccelerationStructure(RenderAccelerationStructureDesc(RenderAccelerationStructureType::TOP_LEVEL, Test.rtTopLevelASBuffer.get(), tlasBuildInfo.accelerationStructureSize));
Test.rtSet->setAccelerationStructure(Test.rtSet->gBVH, Test.rtTopLevelAS.get());
RenderShaderBindingGroups bindingGroups;
RenderPipelineProgram rayGenProgram = Test.rtPipeline->getProgram("ColorRayGen");
RenderPipelineProgram missProgram = Test.rtPipeline->getProgram("ColorMiss");
RenderPipelineProgram hitGroupProgram = Test.rtPipeline->getProgram("ColorHitGroup");
bindingGroups.rayGen = RenderShaderBindingGroup(&rayGenProgram, 1);
bindingGroups.miss = RenderShaderBindingGroup(&missProgram, 1);
bindingGroups.hitGroup = RenderShaderBindingGroup(&hitGroupProgram, 1);
RenderDescriptorSet *rtSetPtr = Test.rtSet->get();
Test.device->setShaderBindingTableInfo(Test.rtShaderBindingTableInfo, bindingGroups, Test.rtPipeline.get(), &rtSetPtr, 1);
const std::vector<uint8_t> tableData = Test.rtShaderBindingTableInfo.tableBufferData;
Test.rtShaderBindingTableBuffer = Test.device->createBuffer(RenderBufferDesc::UploadBuffer(tableData.size(), RenderBufferFlag::SHADER_BINDING_TABLE));
dstData = Test.rtShaderBindingTableBuffer->map();
memcpy(dstData, tableData.data(), tableData.size());
Test.rtShaderBindingTableBuffer->unmap();
// Run command list to copy the vertex buffer and build the BLAS/TLAS.
Test.commandList->begin();
Test.commandList->barriers(RenderBarrierStage::COPY, RenderBufferBarrier(Test.rtVertexBuffer.get(), RenderBufferAccess::WRITE));
Test.commandList->copyBufferRegion(Test.rtVertexBuffer.get(), Test.uploadBuffer.get(), sizeof(BLASVertices));
Test.commandList->barriers(RenderBarrierStage::COMPUTE, RenderBufferBarrier(Test.rtVertexBuffer.get(), RenderBufferAccess::READ));
Test.commandList->buildBottomLevelAS(Test.rtBottomLevelAS.get(), Test.rtScratchBuffer.get(), blasBuildInfo);
Test.commandList->barriers(RenderBarrierStage::NONE, RenderBufferBarrier(Test.rtBottomLevelASBuffer.get(), RenderBufferAccess::READ));
Test.commandList->buildTopLevelAS(Test.rtTopLevelAS.get(), Test.rtScratchBuffer.get(), Test.rtInstancesBuffer.get(), tlasBuildInfo);
Test.commandList->end();
Test.commandQueue->executeCommandLists(Test.commandList.get(), Test.commandFence.get());
Test.commandQueue->waitForCommandFence(Test.commandFence.get());
# endif
}
void TestResize() {
// Resize can be called during window creation by Windows.
if (Test.swapChain == nullptr) {
return;
}
# if ENABLE_SWAP_CHAIN
Test.swapFramebuffers.clear();
Test.swapChain->resize();
Test.swapFramebuffers.resize(Test.swapChain->getTextureCount());
for (uint32_t i = 0; i < Test.swapChain->getTextureCount(); i++) {
const RenderTexture *curTex = Test.swapChain->getTexture(i);
Test.swapFramebuffers[i] = Test.device->createFramebuffer(RenderFramebufferDesc{&curTex, 1});
}
# endif
# if ENABLE_CLEAR
Test.colorTargetMS = Test.device->createTexture(RenderTextureDesc::ColorTarget(Test.swapChain->getWidth(), Test.swapChain->getHeight(), Test.ColorFormat, RenderMultisampling(Test.MSAACount), nullptr));
Test.colorTargetResolved = Test.device->createTexture(RenderTextureDesc::ColorTarget(Test.swapChain->getWidth(), Test.swapChain->getHeight(), Test.ColorFormat, 1, nullptr, RenderTextureFlag::STORAGE | RenderTextureFlag::UNORDERED_ACCESS));
Test.depthTarget = Test.device->createTexture(RenderTextureDesc::DepthTarget(Test.swapChain->getWidth(), Test.swapChain->getHeight(), Test.DepthFormat, RenderMultisampling(Test.MSAACount)));
const RenderTexture *colorTargetPtr = Test.colorTargetMS.get();
Test.framebuffer = Test.device->createFramebuffer(RenderFramebufferDesc(&colorTargetPtr, 1, Test.depthTarget.get()));
# endif
# if ENABLE_COMPUTE
Test.computeSecondSet->setTexture(Test.computeSecondSet->gTarget, Test.colorTarget.get(), RenderTextureLayout::GENERAL);
# endif
# if ENABLE_RT
Test.rtSet->setTexture(Test.rtSet->gOutput, Test.colorTarget.get(), RenderTextureLayout::GENERAL);
# endif
}
void TestDraw() {
// Begin.
Test.commandList->begin();
# if ENABLE_CLEAR
const uint32_t SyncInterval = 1;
const uint32_t width = Test.swapChain->getWidth();
const uint32_t height = Test.swapChain->getHeight();
const RenderViewport viewport(0.0f, 0.0f, float(width), float(height));
const RenderRect scissor(0, 0, width, height);
// Clear.
Test.commandList->setViewports(viewport);
Test.commandList->setScissors(scissor);
Test.commandList->barriers(RenderBarrierStage::GRAPHICS, RenderTextureBarrier(Test.colorTargetMS.get(), RenderTextureLayout::COLOR_WRITE));
Test.commandList->barriers(RenderBarrierStage::GRAPHICS, RenderTextureBarrier(Test.depthTarget.get(), RenderTextureLayout::DEPTH_WRITE));
Test.commandList->setFramebuffer(Test.framebuffer.get());
Test.commandList->clearColor(0, RenderColor(0.0f, 0.0f, 0.5f));
Test.commandList->clearDepth();
# endif
# if ENABLE_RASTER
// Raster.
RasterPushConstant pushConstant;
pushConstant.colorAdd[0] = 0.5f;
pushConstant.colorAdd[1] = 0.25f;
pushConstant.colorAdd[2] = 0.0f;
pushConstant.colorAdd[3] = 0.0f;
pushConstant.textureIndex = 2;
Test.commandList->setPipeline(Test.rasterPipeline.get());
Test.commandList->setGraphicsPipelineLayout(Test.rasterPipelineLayout.get());
Test.commandList->setGraphicsPushConstants(0, &pushConstant);
# if ENABLE_TEXTURE
Test.commandList->setGraphicsDescriptorSet(Test.rasterSet->get(), 0);
# endif
Test.commandList->setVertexBuffers(0, &Test.vertexBufferView, 1, &Test.inputSlot);
Test.commandList->setIndexBuffer(&Test.indexBufferView);
Test.commandList->drawInstanced(3, 1, 0, 0);
Test.commandList->barriers(RenderBarrierStage::COPY, RenderTextureBarrier(Test.depthTarget.get(), RenderTextureLayout::DEPTH_READ));
# endif
# if ENABLE_COMPUTE || ENABLE_RT || ENABLE_CLEAR
Test.commandList->barriers(RenderBarrierStage::COPY, RenderTextureBarrier(Test.colorTargetMS.get(), RenderTextureLayout::RESOLVE_SOURCE));
Test.commandList->barriers(RenderBarrierStage::COPY, RenderTextureBarrier(Test.colorTargetResolved.get(), RenderTextureLayout::RESOLVE_DEST));
Test.commandList->resolveTexture(Test.colorTargetResolved.get(), Test.colorTargetMS.get());
# endif
# if ENABLE_COMPUTE || ENABLE_RT
Test.commandList->barriers(RenderBarrierStage::COMPUTE, RenderTextureBarrier(Test.colorTargetResolved.get(), RenderTextureLayout::GENERAL));
# endif
# if ENABLE_COMPUTE
const uint32_t GroupCount = 8;
ComputePushConstant pushCostant;
pushCostant.Resolution[0] = width;
pushCostant.Resolution[1] = height;
pushCostant.Multiply[0] = 0.5f;
pushCostant.Multiply[1] = 0.5f;
pushCostant.Multiply[2] = 1.0f;
pushCostant.Multiply[3] = 1.0f;
Test.commandList->setPipeline(Test.computePipeline.get());
Test.commandList->setComputePipelineLayout(Test.computePipelineLayout.get());
Test.commandList->setComputePushConstants(0, &pushCostant);
Test.commandList->setComputeDescriptorSet(Test.computeFirstSet->get(), 0);
Test.commandList->setComputeDescriptorSet(Test.computeSecondSet->get(), 1);
Test.commandList->dispatch((width + GroupCount - 1) / GroupCount, (height + GroupCount - 1) / GroupCount, 1);
# endif
# if ENABLE_RT
// RT.
Test.commandList->barriers(RenderBarrierStage::COMPUTE, RenderTextureBarrier(Test.colorTargetResolved.get(), RenderTextureLayout::GENERAL));
Test.commandList->setPipeline(Test.rtPipeline.get());
Test.commandList->setRaytracingPipelineLayout(Test.rtPipelineLayout.get());
Test.commandList->setRaytracingDescriptorSet(Test.rtSet->get(), 0);
Test.commandList->traceRays(width, height, 1, Test.rtShaderBindingTableBuffer.get(), Test.rtShaderBindingTableInfo.groups);
# endif
# if ENABLE_SWAP_CHAIN
const uint32_t swapChainTextureIndex = Test.swapChain->getTextureIndex();
RenderTexture *swapChainTexture = Test.swapChain->getTexture(swapChainTextureIndex);
RenderFramebuffer *swapFramebuffer = Test.swapFramebuffers[swapChainTextureIndex].get();
Test.commandList->setViewports(viewport);
Test.commandList->setScissors(scissor);
Test.commandList->barriers(RenderBarrierStage::GRAPHICS, RenderTextureBarrier(swapChainTexture, RenderTextureLayout::COLOR_WRITE));
Test.commandList->setFramebuffer(swapFramebuffer);
# endif
# if ENABLE_CLEAR
Test.commandList->barriers(RenderBarrierStage::GRAPHICS, RenderTextureBarrier(Test.colorTargetResolved.get(), RenderTextureLayout::SHADER_READ));
Test.commandList->clearColor(0, RenderColor(0.0f, 0.0f, 0.0f));
Test.commandList->setPipeline(Test.postPipeline.get());
Test.commandList->setGraphicsPipelineLayout(Test.postPipelineLayout.get());
Test.postSet->setTexture(0, Test.colorTargetResolved.get(), RenderTextureLayout::SHADER_READ);
Test.commandList->setGraphicsDescriptorSet(Test.postSet.get(), 0);
Test.commandList->drawInstanced(3, 1, 0, 0);
# endif
# if ENABLE_SWAP_CHAIN
Test.commandList->barriers(RenderBarrierStage::NONE, RenderTextureBarrier(swapChainTexture, RenderTextureLayout::PRESENT));
# endif
// End.
Test.commandList->end();
Test.commandQueue->executeCommandLists(Test.commandList.get(), Test.commandFence.get());
# if ENABLE_SWAP_CHAIN
Test.swapChain->present();
# endif
Test.commandQueue->waitForCommandFence(Test.commandFence.get());
}
void TestShutdown() {
Test.rtParamsBuffer.reset(nullptr);
Test.rtVertexBuffer.reset(nullptr);
Test.rtScratchBuffer.reset(nullptr);
Test.rtInstancesBuffer.reset(nullptr);
Test.rtBottomLevelASBuffer.reset(nullptr);
Test.rtTopLevelASBuffer.reset(nullptr);
Test.rtShaderBindingTableBuffer.reset(nullptr);
Test.uploadBuffer.reset(nullptr);
Test.blueNoiseTexture.reset(nullptr);
Test.vertexBuffer.reset(nullptr);
Test.indexBuffer.reset(nullptr);
Test.rasterPipeline.reset(nullptr);
Test.computePipeline.reset(nullptr);
Test.rtPipeline.reset(nullptr);
Test.postPipeline.reset(nullptr);
Test.rasterPipelineLayout.reset(nullptr);
Test.computePipelineLayout.reset(nullptr);
Test.rtPipelineLayout.reset(nullptr);
Test.postPipelineLayout.reset(nullptr);
Test.rtSet.reset(nullptr);
Test.rasterSet.reset(nullptr);
Test.computeFirstSet.reset(nullptr);
Test.computeSecondSet.reset(nullptr);
Test.postSet.reset(nullptr);
Test.linearSampler.reset(nullptr);
Test.postSampler.reset(nullptr);
Test.colorTargetMS.reset(nullptr);
Test.colorTargetResolved.reset(nullptr);
Test.framebuffer.reset(nullptr);
Test.swapFramebuffers.clear();
Test.commandList.reset(nullptr);
Test.commandFence.reset(nullptr);
Test.swapChain.reset(nullptr);
Test.commandQueue.reset(nullptr);
Test.device.reset(nullptr);
}
#if defined(_WIN64)
static LRESULT CALLBACK TestWndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) {
switch (message) {
case WM_CLOSE:
PostQuitMessage(0);
break;
case WM_SIZE:
TestResize();
return 0;
case WM_PAINT:
TestDraw();
return 0;
default:
return DefWindowProc(hWnd, message, wParam, lParam);
}
return 0;
}
static HWND TestCreateWindow() {
// Register window class.
WNDCLASS wc;
memset(&wc, 0, sizeof(WNDCLASS));
wc.lpfnWndProc = TestWndProc;
wc.hInstance = GetModuleHandle(0);
wc.hbrBackground = (HBRUSH)(COLOR_BACKGROUND);
wc.lpszClassName = "RenderInterfaceTest";
RegisterClass(&wc);
// Create window.
const int Width = 1280;
const int Height = 720;
RECT rect;
UINT dwStyle = WS_OVERLAPPEDWINDOW | WS_VISIBLE;
rect.left = (GetSystemMetrics(SM_CXSCREEN) - Width) / 2;
rect.top = (GetSystemMetrics(SM_CYSCREEN) - Height) / 2;
rect.right = rect.left + Width;
rect.bottom = rect.top + Height;
AdjustWindowRectEx(&rect, dwStyle, 0, 0);
return CreateWindow(wc.lpszClassName, "Render Interface Test", dwStyle, rect.left, rect.top, rect.right - rect.left, rect.bottom - rect.top, 0, 0, wc.hInstance, NULL);
}
void RenderInterfaceTest(RenderInterface *renderInterface) {
HWND hwnd = TestCreateWindow();
TestInitialize(renderInterface, hwnd);
TestResize();
// Message loop.
MSG msg = {};
while (msg.message != WM_QUIT) {
if (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE)) {
TranslateMessage(&msg);
DispatchMessage(&msg);
}
}
TestShutdown();
DestroyWindow(hwnd);
}
#elif defined(__ANDROID__)
void RenderInterfaceTest(RenderInterface* renderInterface) {
assert(false);
}
#elif defined(__linux__)
void RenderInterfaceTest(RenderInterface* renderInterface) {
Display* display = XOpenDisplay(nullptr);
int blackColor = BlackPixel(display, DefaultScreen(display));
Window window = XCreateSimpleWindow(display, DefaultRootWindow(display),
0, 0, 1280, 720, 0, blackColor, blackColor);
XSelectInput(display, window, StructureNotifyMask);
// Map the window and wait for the notify event to come in.
XMapWindow(display, window);
while (true) {
XEvent event;
XNextEvent(display, &event);
if (event.type == MapNotify) {
break;
}
}
// Set up the delete window protocol.
Atom wmDeleteMessage = XInternAtom(display, "WM_DELETE_WINDOW", False);
XSetWMProtocols(display, window, &wmDeleteMessage, 1);
TestInitialize(renderInterface, {display, window});
TestResize();
TestDraw();
// Loop until the window is closed.
std::chrono::system_clock::time_point prev_frame = std::chrono::system_clock::now();
bool running = true;
while (running) {
if (XPending(display) > 0) {
XEvent event;
XNextEvent(display, &event);
switch (event.type) {
case Expose:
TestDraw();
break;
case ClientMessage:
if (event.xclient.data.l[0] == wmDeleteMessage)
running = false;
break;
default:
break;
}
}
using namespace std::chrono_literals;
std::this_thread::sleep_for(1ms);
auto now_time = std::chrono::system_clock::now();
if (now_time - prev_frame > 16666us) {
prev_frame = now_time;
TestDraw();
}
}
TestShutdown();
XDestroyWindow(display, window);
}
#elif defined(__APPLE__)
void RenderInterfaceTest(RenderInterface* renderInterface) {
assert(false);
}
#endif
};

View File

@ -0,0 +1,26 @@
//
// RT64
//
struct Constants {
float4 Multiply;
uint2 Resolution;
};
[[vk::push_constant]] ConstantBuffer<Constants> gConstants : register(b0);
Texture2D<float4> gBlueNoiseTexture : register(t1);
SamplerState gSampler : register(s2);
[[vk::image_format("rgba8")]]
RWTexture2D<float4> gTarget : register(u16, space1);
[numthreads(8, 8, 1)]
void CSMain(uint2 coord : SV_DispatchThreadID) {
if (any(coord >= gConstants.Resolution)) {
return;
}
float2 blueNoiseUV = float2(coord) / float2(gConstants.Resolution);
float4 blueNoise = float4(gBlueNoiseTexture.SampleLevel(gSampler, blueNoiseUV, 0).rgb, 1.0f);
gTarget[coord] *= (blueNoise * gConstants.Multiply);
}

View File

@ -0,0 +1,19 @@
//
// RT64
//
struct Constants {
float4 colorAdd;
uint textureIndex;
};
[[vk::push_constant]] ConstantBuffer<Constants> gConstants : register(b0);
SamplerState gSampler : register(s1);
Texture2D<float4> gTexture[] : register(t2);
float4 PSMain(in float4 pos : SV_Position, in float2 uv : TEXCOORD) : SV_TARGET {
float4 result = float4(gTexture[NonUniformResourceIndex(gConstants.textureIndex)].SampleLevel(gSampler, uv, 0).rgb, 1.0f);
result += gConstants.colorAdd;
return result;
}

View File

@ -0,0 +1,11 @@
//
// RT64
//
Texture2D<float4> gTexture : register(t1);
SamplerState gSampler : register(s2);
float4 PSMain(in float4 pos : SV_Position, in float2 uv : TEXCOORD) : SV_TARGET {
float4 result = float4(gTexture.SampleLevel(gSampler, uv, 0).rgb, 1.0f);
return result;
}

View File

@ -0,0 +1,9 @@
//
// RT64
//
void VSMain(in uint id : SV_VertexID, out float4 pos : SV_Position, out float2 uv : TEXCOORD0) {
uv.x = (id == 2) ? 2.0f : 0.0f;
uv.y = (id == 1) ? 2.0f : 0.0f;
pos = float4(uv * float2(2.0f, -2.0f) + float2(-1.0f, 1.0f), 1.0f, 1.0f);
}

View File

@ -0,0 +1,44 @@
//
// RT64
//
struct Attributes {
float2 bary;
};
struct Payload {
float4 color;
};
struct BufferParams {
float3 rgbMultiplier;
uint3 pad;
};
RaytracingAccelerationStructure gBVH : register(t0);
RWTexture2D<float4> gOutput : register(u1);
StructuredBuffer<BufferParams> gBufferParams : register(t2);
[shader("raygeneration")]
void ColorRayGen() {
RayDesc ray;
ray.Origin = float3(float2(DispatchRaysIndex().xy) / float2(DispatchRaysDimensions().xy), 0.0f);
ray.Direction = float3(0.0f, 0.0f, 1.0f);
ray.TMin = 1e-6f;
ray.TMax = 1e6f;
Payload payload;
payload.color = float4(0.0f, 0.5f, 0.0f, 1.0f);
TraceRay(gBVH, RAY_FLAG_NONE, 0xFF, 0, 0, 0, ray, payload);
gOutput[DispatchRaysIndex().xy] = payload.color;
}
[shader("closesthit")]
void ColorClosestHit(inout Payload payload, in Attributes attr) {
payload.color = float4(1.0f, attr.bary.xy, 1.0f) * float4(gBufferParams[0].rgbMultiplier, 1.0f);
}
[shader("miss")]
void ColorMiss(inout Payload payload) {
payload.color = float4(0.25f, 0.25f, 0.5f, 1.0f) * float4(gBufferParams[1].rgbMultiplier, 1.0f);
}

View File

@ -0,0 +1,8 @@
//
// RT64
//
void VSMain(in float2 vertexPos : POSITION, in float2 vertexUV : TEXCOORD, out float4 pos : SV_POSITION, out float2 uv : TEXCOORD) {
pos = float4(vertexPos, 1.0f, 1.0f);
uv = vertexUV;
}

View File

@ -45,6 +45,8 @@ namespace RT64 {
SetThreadDescription(GetCurrentThread(), nameWide.c_str());
# elif defined(__linux__)
pthread_setname_np(pthread_self(), str.c_str());
# elif defined(__APPLE__)
pthread_setname_np(str.c_str());
# else
static_assert(false, "Unimplemented");
# endif
@ -53,7 +55,7 @@ namespace RT64 {
void Thread::setCurrentThreadPriority(Priority priority) {
# if defined(_WIN32)
SetThreadPriority(GetCurrentThread(), toWindowsPriority(priority));
# elif defined(__linux__)
# elif defined(__linux__) || defined(__APPLE__)
// On Linux, thread priorities can't be changed under the default scheduler policy (SCHED_OTHER) and the other policies
// that are available without root privileges are lower priority. Instead you can set the thread's "nice" value, which ranges
// from -20 to 19 (lower being higher priority). However, by strict POSIX spec "nice" is meant to be per-process instead of

@ -1 +1 @@
Subproject commit 46e63bcacad9e20e97f221fe492482d84a88210c
Subproject commit 9d592dfcb0aac9493865f253a855b558820be06d

View File

@ -89,7 +89,7 @@ namespace RT64 {
bounds.height = rect.bottom - rect.top;
# elif defined(__ANDROID__)
static_assert(false && "Android unimplemented");
# elif defined(__linux__)
# elif defined(__linux__) || defined(__APPLE__)
if (SDL_VideoInit(nullptr) != 0) {
printf("Failed to init SDL2 video: %s\n", SDL_GetError());
assert(false && "Failed to init SDL2 video");
@ -123,6 +123,8 @@ namespace RT64 {
# elif defined(__linux__)
windowHandle.display = wmInfo.info.x11.display;
windowHandle.window = wmInfo.info.x11.window;
# elif defined(__APPLE__)
windowHandle.window = wmInfo.info.cocoa.window;
# else
static_assert(false && "Android unimplemented");
# endif
@ -133,6 +135,10 @@ namespace RT64 {
# ifdef _WIN32
setup(windowHandle, listener, GetCurrentThreadId());
# elif defined(__APPLE__)
uint64_t tid;
pthread_threadid_np(nullptr, &tid);
setup(windowHandle, listener, tid);
# else
setup(windowHandle, listener, pthread_self());
# endif

View File

@ -3,6 +3,7 @@
//
#include <cstring>
#include <algorithm>
#include "common/rt64_thread.h"
@ -91,7 +92,7 @@ namespace RT64 {
// Recreate the buffer pair.
const uint64_t BlockAlignment = 256;
bufferPair.allocatedSize = std::max((requiredSize * 3) / 2, BlockAlignment);
bufferPair.allocatedSize = std::max(((uint64_t)requiredSize * 3) / 2, BlockAlignment);
bufferPair.allocatedSize = roundUp(bufferPair.allocatedSize, BlockAlignment);
bufferPair.uploadBuffer = worker->device->createBuffer(RenderBufferDesc::UploadBuffer(bufferPair.allocatedSize));
bufferPair.defaultBuffer = worker->device->createBuffer(RenderBufferDesc::DefaultBuffer(bufferPair.allocatedSize, u.bufferFlags));

View File

@ -20,6 +20,8 @@
#undef None
#undef Status
#undef LockMask
#elif defined(__APPLE__)
typedef struct _NSWindow NSWindow;
#endif
namespace RT64 {
@ -37,6 +39,14 @@ namespace RT64 {
}
bool operator!=(const struct RenderWindow& rhs) const { return !(*this == rhs); }
};
#elif defined(__APPLE__)
struct RenderWindow {
NSWindow* window;
bool operator==(const struct RenderWindow& rhs) const {
return window == rhs.window;
}
bool operator!=(const struct RenderWindow& rhs) const { return !(*this == rhs); }
};
#else
static_assert(false, "RenderWindow was not defined for this platform.");
#endif