diff --git a/tests/RHI/D3D12/unit/CMakeLists.txt b/tests/RHI/D3D12/unit/CMakeLists.txt index a135f6e8..2a2a9bf0 100644 --- a/tests/RHI/D3D12/unit/CMakeLists.txt +++ b/tests/RHI/D3D12/unit/CMakeLists.txt @@ -19,6 +19,7 @@ set(TEST_SOURCES test_pipeline_state.cpp test_views.cpp test_swap_chain.cpp + test_backend_specific.cpp ) add_executable(rhi_d3d12_tests ${TEST_SOURCES}) diff --git a/tests/RHI/D3D12/unit/test_backend_specific.cpp b/tests/RHI/D3D12/unit/test_backend_specific.cpp new file mode 100644 index 00000000..e500dddb --- /dev/null +++ b/tests/RHI/D3D12/unit/test_backend_specific.cpp @@ -0,0 +1,248 @@ +#include "fixtures/D3D12TestFixture.h" + +#include "XCEngine/RHI/D3D12/D3D12DescriptorSet.h" +#include "XCEngine/RHI/D3D12/D3D12PipelineLayout.h" +#include "XCEngine/RHI/RHIDescriptorPool.h" +#include "XCEngine/RHI/RHIEnums.h" +#include "XCEngine/RHI/RHIPipelineLayout.h" + +using namespace XCEngine::RHI; + +TEST_F(D3D12TestFixture, DescriptorSet_MixedBindings_AssignDescriptorIndicesByType) { + DescriptorPoolDesc poolDesc = {}; + poolDesc.type = DescriptorHeapType::CBV_SRV_UAV; + poolDesc.descriptorCount = 4; + poolDesc.shaderVisible = true; + + RHIDescriptorPool* pool = GetDevice()->CreateDescriptorPool(poolDesc); + ASSERT_NE(pool, nullptr); + + DescriptorSetLayoutBinding bindings[3] = {}; + bindings[0].binding = 2; + bindings[0].type = static_cast(DescriptorType::UAV); + bindings[0].count = 1; + bindings[1].binding = 0; + bindings[1].type = static_cast(DescriptorType::CBV); + bindings[1].count = 1; + bindings[2].binding = 1; + bindings[2].type = static_cast(DescriptorType::SRV); + bindings[2].count = 1; + + DescriptorSetLayoutDesc layoutDesc = {}; + layoutDesc.bindings = bindings; + layoutDesc.bindingCount = 3; + + RHIDescriptorSet* firstSet = pool->AllocateSet(layoutDesc); + RHIDescriptorSet* secondSet = pool->AllocateSet(layoutDesc); + ASSERT_NE(firstSet, nullptr); + ASSERT_NE(secondSet, nullptr); + + auto* firstD3D12Set = static_cast(firstSet); + auto* secondD3D12Set = static_cast(secondSet); + EXPECT_EQ(firstD3D12Set->GetCount(), 2u); + EXPECT_EQ(firstD3D12Set->GetDescriptorIndexForBinding(1), 0u); + EXPECT_EQ(firstD3D12Set->GetDescriptorIndexForBinding(2), 1u); + EXPECT_EQ(firstD3D12Set->GetDescriptorIndexForBinding(0), UINT32_MAX); + EXPECT_EQ(firstD3D12Set->GetOffset(), 0u); + EXPECT_EQ(secondD3D12Set->GetOffset(), 2u); + + firstSet->Shutdown(); + delete firstSet; + secondSet->Shutdown(); + delete secondSet; + pool->Shutdown(); + delete pool; +} + +TEST_F(D3D12TestFixture, DescriptorSet_MultipleConstantBuffersUploadIndependently) { + DescriptorPoolDesc poolDesc = {}; + poolDesc.type = DescriptorHeapType::CBV_SRV_UAV; + poolDesc.descriptorCount = 1; + poolDesc.shaderVisible = false; + + RHIDescriptorPool* pool = GetDevice()->CreateDescriptorPool(poolDesc); + ASSERT_NE(pool, nullptr); + + DescriptorSetLayoutBinding bindings[2] = {}; + bindings[0].binding = 0; + bindings[0].type = static_cast(DescriptorType::CBV); + bindings[0].count = 1; + bindings[1].binding = 1; + bindings[1].type = static_cast(DescriptorType::CBV); + bindings[1].count = 1; + + DescriptorSetLayoutDesc layoutDesc = {}; + layoutDesc.bindings = bindings; + layoutDesc.bindingCount = 2; + + RHIDescriptorSet* set = pool->AllocateSet(layoutDesc); + ASSERT_NE(set, nullptr); + + auto* d3d12Set = static_cast(set); + const float firstData[16] = { 1.0f, 0.0f, 0.0f, 0.0f }; + const float secondData[16] = { 2.0f, 0.0f, 0.0f, 0.0f }; + d3d12Set->WriteConstant(0, firstData, sizeof(firstData)); + d3d12Set->WriteConstant(1, secondData, sizeof(secondData)); + + ASSERT_TRUE(d3d12Set->UploadConstantBuffer(0)); + ASSERT_TRUE(d3d12Set->UploadConstantBuffer(1)); + + const D3D12_GPU_VIRTUAL_ADDRESS firstAddress = d3d12Set->GetConstantBufferGPUAddress(0); + const D3D12_GPU_VIRTUAL_ADDRESS secondAddress = d3d12Set->GetConstantBufferGPUAddress(1); + EXPECT_NE(firstAddress, 0u); + EXPECT_NE(secondAddress, 0u); + EXPECT_NE(firstAddress, secondAddress); + + set->Shutdown(); + delete set; + pool->Shutdown(); + delete pool; +} + +TEST_F(D3D12TestFixture, PipelineLayout_TracksDistinctBindingClasses) { + RHIPipelineLayoutDesc desc = {}; + desc.constantBufferCount = 2; + desc.textureCount = 1; + desc.uavCount = 1; + desc.samplerCount = 1; + + RHIPipelineLayout* layout = GetDevice()->CreatePipelineLayout(desc); + ASSERT_NE(layout, nullptr); + + auto* d3d12Layout = static_cast(layout); + EXPECT_TRUE(d3d12Layout->HasConstantBufferBinding(0)); + EXPECT_TRUE(d3d12Layout->HasConstantBufferBinding(1)); + EXPECT_FALSE(d3d12Layout->HasConstantBufferBinding(2)); + + EXPECT_TRUE(d3d12Layout->HasShaderResourceTable()); + EXPECT_TRUE(d3d12Layout->HasUnorderedAccessTable()); + EXPECT_TRUE(d3d12Layout->HasSamplerTable()); + + EXPECT_NE( + d3d12Layout->GetConstantBufferRootParameterIndex(0), + d3d12Layout->GetConstantBufferRootParameterIndex(1)); + EXPECT_NE( + d3d12Layout->GetShaderResourceTableRootParameterIndex(), + d3d12Layout->GetUnorderedAccessTableRootParameterIndex()); + EXPECT_NE( + d3d12Layout->GetUnorderedAccessTableRootParameterIndex(), + d3d12Layout->GetSamplerTableRootParameterIndex()); + + layout->Shutdown(); + delete layout; +} + +TEST_F(D3D12TestFixture, PipelineLayout_InfersBindingClassesFromSetLayouts) { + DescriptorSetLayoutBinding set0Bindings[1] = {}; + set0Bindings[0].binding = 0; + set0Bindings[0].type = static_cast(DescriptorType::CBV); + set0Bindings[0].count = 1; + + DescriptorSetLayoutBinding set1Bindings[1] = {}; + set1Bindings[0].binding = 0; + set1Bindings[0].type = static_cast(DescriptorType::SRV); + set1Bindings[0].count = 1; + + DescriptorSetLayoutBinding set2Bindings[1] = {}; + set2Bindings[0].binding = 0; + set2Bindings[0].type = static_cast(DescriptorType::UAV); + set2Bindings[0].count = 1; + + DescriptorSetLayoutBinding set3Bindings[1] = {}; + set3Bindings[0].binding = 0; + set3Bindings[0].type = static_cast(DescriptorType::Sampler); + set3Bindings[0].count = 1; + + DescriptorSetLayoutDesc setLayouts[4] = {}; + setLayouts[0].bindings = set0Bindings; + setLayouts[0].bindingCount = 1; + setLayouts[1].bindings = set1Bindings; + setLayouts[1].bindingCount = 1; + setLayouts[2].bindings = set2Bindings; + setLayouts[2].bindingCount = 1; + setLayouts[3].bindings = set3Bindings; + setLayouts[3].bindingCount = 1; + + RHIPipelineLayoutDesc desc = {}; + desc.setLayouts = setLayouts; + desc.setLayoutCount = 4; + + RHIPipelineLayout* layout = GetDevice()->CreatePipelineLayout(desc); + ASSERT_NE(layout, nullptr); + + auto* d3d12Layout = static_cast(layout); + EXPECT_TRUE(d3d12Layout->UsesSetLayouts()); + EXPECT_EQ(d3d12Layout->GetSetLayoutCount(), 4u); + EXPECT_TRUE(d3d12Layout->HasConstantBufferBinding(0, 0)); + EXPECT_TRUE(d3d12Layout->HasShaderResourceTable(1)); + EXPECT_TRUE(d3d12Layout->HasUnorderedAccessTable(2)); + EXPECT_TRUE(d3d12Layout->HasSamplerTable(3)); + EXPECT_EQ(d3d12Layout->GetDesc().constantBufferCount, 1u); + EXPECT_EQ(d3d12Layout->GetDesc().textureCount, 1u); + EXPECT_EQ(d3d12Layout->GetDesc().uavCount, 1u); + EXPECT_EQ(d3d12Layout->GetDesc().samplerCount, 1u); + + layout->Shutdown(); + delete layout; +} + +TEST_F(D3D12TestFixture, PipelineLayout_SeparatesOverlappingBindingsAcrossSetSlots) { + DescriptorSetLayoutBinding set0Bindings[2] = {}; + set0Bindings[0].binding = 0; + set0Bindings[0].type = static_cast(DescriptorType::CBV); + set0Bindings[0].count = 1; + set0Bindings[1].binding = 0; + set0Bindings[1].type = static_cast(DescriptorType::SRV); + set0Bindings[1].count = 1; + + DescriptorSetLayoutBinding set1Bindings[2] = {}; + set1Bindings[0].binding = 0; + set1Bindings[0].type = static_cast(DescriptorType::CBV); + set1Bindings[0].count = 1; + set1Bindings[1].binding = 0; + set1Bindings[1].type = static_cast(DescriptorType::SRV); + set1Bindings[1].count = 1; + + DescriptorSetLayoutBinding set2Bindings[1] = {}; + set2Bindings[0].binding = 0; + set2Bindings[0].type = static_cast(DescriptorType::Sampler); + set2Bindings[0].count = 1; + + DescriptorSetLayoutDesc setLayouts[3] = {}; + setLayouts[0].bindings = set0Bindings; + setLayouts[0].bindingCount = 2; + setLayouts[1].bindings = set1Bindings; + setLayouts[1].bindingCount = 2; + setLayouts[2].bindings = set2Bindings; + setLayouts[2].bindingCount = 1; + + RHIPipelineLayoutDesc desc = {}; + desc.setLayouts = setLayouts; + desc.setLayoutCount = 3; + + RHIPipelineLayout* layout = GetDevice()->CreatePipelineLayout(desc); + ASSERT_NE(layout, nullptr); + + auto* d3d12Layout = static_cast(layout); + EXPECT_TRUE(d3d12Layout->UsesSetLayouts()); + EXPECT_TRUE(d3d12Layout->HasConstantBufferBinding(0, 0)); + EXPECT_TRUE(d3d12Layout->HasConstantBufferBinding(1, 0)); + EXPECT_FALSE(d3d12Layout->HasConstantBufferBinding(2, 0)); + EXPECT_NE( + d3d12Layout->GetConstantBufferRootParameterIndex(0, 0), + d3d12Layout->GetConstantBufferRootParameterIndex(1, 0)); + + EXPECT_TRUE(d3d12Layout->HasShaderResourceTable(0)); + EXPECT_TRUE(d3d12Layout->HasShaderResourceTable(1)); + EXPECT_FALSE(d3d12Layout->HasShaderResourceTable(2)); + EXPECT_NE( + d3d12Layout->GetShaderResourceTableRootParameterIndex(0), + d3d12Layout->GetShaderResourceTableRootParameterIndex(1)); + + EXPECT_FALSE(d3d12Layout->HasSamplerTable(0)); + EXPECT_FALSE(d3d12Layout->HasSamplerTable(1)); + EXPECT_TRUE(d3d12Layout->HasSamplerTable(2)); + + layout->Shutdown(); + delete layout; +} diff --git a/tests/RHI/OpenGL/unit/CMakeLists.txt b/tests/RHI/OpenGL/unit/CMakeLists.txt index c430dbd7..d76beeb0 100644 --- a/tests/RHI/OpenGL/unit/CMakeLists.txt +++ b/tests/RHI/OpenGL/unit/CMakeLists.txt @@ -25,6 +25,7 @@ set(TEST_SOURCES test_depth_stencil_view.cpp test_swap_chain.cpp test_sampler.cpp + test_backend_specific.cpp ) add_executable(rhi_opengl_tests ${TEST_SOURCES}) @@ -44,4 +45,4 @@ target_include_directories(rhi_opengl_tests PRIVATE enable_testing() include(GoogleTest) -gtest_discover_tests(rhi_opengl_tests) \ No newline at end of file +gtest_discover_tests(rhi_opengl_tests) diff --git a/tests/RHI/OpenGL/unit/test_backend_specific.cpp b/tests/RHI/OpenGL/unit/test_backend_specific.cpp new file mode 100644 index 00000000..f6095341 --- /dev/null +++ b/tests/RHI/OpenGL/unit/test_backend_specific.cpp @@ -0,0 +1,737 @@ +#include "fixtures/OpenGLTestFixture.h" + +#include "XCEngine/RHI/OpenGL/OpenGLDescriptorSet.h" +#include "XCEngine/RHI/OpenGL/OpenGLPipelineLayout.h" +#include "XCEngine/RHI/OpenGL/OpenGLResourceView.h" +#include "XCEngine/RHI/OpenGL/OpenGLSampler.h" +#include "XCEngine/RHI/RHIBuffer.h" +#include "XCEngine/RHI/RHICommandList.h" +#include "XCEngine/RHI/RHICommandQueue.h" +#include "XCEngine/RHI/RHIDescriptorPool.h" +#include "XCEngine/RHI/RHIEnums.h" +#include "XCEngine/RHI/RHIPipelineLayout.h" +#include "XCEngine/RHI/RHIPipelineState.h" +#include "XCEngine/RHI/RHIResourceView.h" +#include "XCEngine/RHI/RHIShader.h" +#include "XCEngine/RHI/RHISampler.h" +#include "XCEngine/RHI/RHISwapChain.h" +#include "XCEngine/RHI/RHITexture.h" + +#include +#include +#include + +using namespace XCEngine::RHI; + +TEST_F(OpenGLTestFixture, Device_Initialize_UnifiedPath_CanCreateSwapChain) { + auto* device = new OpenGLDevice(); + ASSERT_NE(device, nullptr); + + RHIDeviceDesc deviceDesc = {}; + ASSERT_TRUE(device->Initialize(deviceDesc)); + + CommandQueueDesc queueDesc = {}; + queueDesc.queueType = static_cast(CommandQueueType::Direct); + RHICommandQueue* queue = device->CreateCommandQueue(queueDesc); + ASSERT_NE(queue, nullptr); + + SwapChainDesc swapDesc = {}; + swapDesc.windowHandle = GetWindow(); + swapDesc.width = 320; + swapDesc.height = 180; + RHISwapChain* swapChain = device->CreateSwapChain(swapDesc, queue); + ASSERT_NE(swapChain, nullptr); + + swapChain->Present(0, 0); + + swapChain->Shutdown(); + delete swapChain; + queue->Shutdown(); + delete queue; + device->Shutdown(); + delete device; +} + +TEST_F(OpenGLTestFixture, CommandList_SetRenderTargets_BindsColorAndDepthAttachments) { + TextureDesc colorDesc = {}; + colorDesc.width = 128; + colorDesc.height = 128; + colorDesc.format = static_cast(Format::R8G8B8A8_UNorm); + colorDesc.textureType = static_cast(TextureType::Texture2D); + + TextureDesc depthDesc = {}; + depthDesc.width = 128; + depthDesc.height = 128; + depthDesc.format = static_cast(Format::D24_UNorm_S8_UInt); + depthDesc.textureType = static_cast(TextureType::Texture2D); + + RHITexture* colorTexture = GetDevice()->CreateTexture(colorDesc); + RHITexture* depthTexture = GetDevice()->CreateTexture(depthDesc); + ASSERT_NE(colorTexture, nullptr); + ASSERT_NE(depthTexture, nullptr); + + ResourceViewDesc colorViewDesc = {}; + colorViewDesc.format = colorDesc.format; + RHIResourceView* rtv = GetDevice()->CreateRenderTargetView(colorTexture, colorViewDesc); + + ResourceViewDesc depthViewDesc = {}; + depthViewDesc.format = depthDesc.format; + RHIResourceView* dsv = GetDevice()->CreateDepthStencilView(depthTexture, depthViewDesc); + ASSERT_NE(rtv, nullptr); + ASSERT_NE(dsv, nullptr); + + CommandListDesc cmdDesc = {}; + cmdDesc.commandListType = static_cast(CommandQueueType::Direct); + RHICommandList* cmdList = GetDevice()->CreateCommandList(cmdDesc); + ASSERT_NE(cmdList, nullptr); + + cmdList->Reset(); + cmdList->SetRenderTargets(1, &rtv, dsv); + + GLint framebuffer = 0; + glGetIntegerv(GL_DRAW_FRAMEBUFFER_BINDING, &framebuffer); + EXPECT_NE(framebuffer, 0); + EXPECT_EQ(glCheckFramebufferStatus(GL_DRAW_FRAMEBUFFER), GL_FRAMEBUFFER_COMPLETE); + + GLint colorAttachment = 0; + glGetFramebufferAttachmentParameteriv( + GL_DRAW_FRAMEBUFFER, + GL_COLOR_ATTACHMENT0, + GL_FRAMEBUFFER_ATTACHMENT_OBJECT_NAME, + &colorAttachment); + EXPECT_EQ(static_cast(colorAttachment), static_cast(rtv)->GetTexture()); + + GLint depthAttachment = 0; + glGetFramebufferAttachmentParameteriv( + GL_DRAW_FRAMEBUFFER, + GL_DEPTH_ATTACHMENT, + GL_FRAMEBUFFER_ATTACHMENT_OBJECT_NAME, + &depthAttachment); + EXPECT_EQ(static_cast(depthAttachment), static_cast(dsv)->GetTexture()); + + cmdList->Close(); + + cmdList->Shutdown(); + delete cmdList; + delete dsv; + delete rtv; + depthTexture->Shutdown(); + delete depthTexture; + colorTexture->Shutdown(); + delete colorTexture; +} + +TEST_F(OpenGLTestFixture, CommandList_SetRenderTargets_BindsMultipleColorAttachments) { + TextureDesc texDesc = {}; + texDesc.width = 128; + texDesc.height = 128; + texDesc.format = static_cast(Format::R8G8B8A8_UNorm); + texDesc.textureType = static_cast(TextureType::Texture2D); + + RHITexture* texture0 = GetDevice()->CreateTexture(texDesc); + RHITexture* texture1 = GetDevice()->CreateTexture(texDesc); + ASSERT_NE(texture0, nullptr); + ASSERT_NE(texture1, nullptr); + + ResourceViewDesc viewDesc = {}; + viewDesc.format = texDesc.format; + RHIResourceView* rtv0 = GetDevice()->CreateRenderTargetView(texture0, viewDesc); + RHIResourceView* rtv1 = GetDevice()->CreateRenderTargetView(texture1, viewDesc); + ASSERT_NE(rtv0, nullptr); + ASSERT_NE(rtv1, nullptr); + + RHIResourceView* rtvs[] = { rtv0, rtv1 }; + + CommandListDesc cmdDesc = {}; + cmdDesc.commandListType = static_cast(CommandQueueType::Direct); + RHICommandList* cmdList = GetDevice()->CreateCommandList(cmdDesc); + ASSERT_NE(cmdList, nullptr); + + cmdList->Reset(); + cmdList->SetRenderTargets(2, rtvs, nullptr); + + GLint framebuffer = 0; + glGetIntegerv(GL_DRAW_FRAMEBUFFER_BINDING, &framebuffer); + EXPECT_NE(framebuffer, 0); + EXPECT_EQ(glCheckFramebufferStatus(GL_DRAW_FRAMEBUFFER), GL_FRAMEBUFFER_COMPLETE); + + GLint colorAttachment0 = 0; + glGetFramebufferAttachmentParameteriv( + GL_DRAW_FRAMEBUFFER, + GL_COLOR_ATTACHMENT0, + GL_FRAMEBUFFER_ATTACHMENT_OBJECT_NAME, + &colorAttachment0); + EXPECT_EQ(static_cast(colorAttachment0), static_cast(rtv0)->GetTexture()); + + GLint colorAttachment1 = 0; + glGetFramebufferAttachmentParameteriv( + GL_DRAW_FRAMEBUFFER, + GL_COLOR_ATTACHMENT1, + GL_FRAMEBUFFER_ATTACHMENT_OBJECT_NAME, + &colorAttachment1); + EXPECT_EQ(static_cast(colorAttachment1), static_cast(rtv1)->GetTexture()); + + cmdList->Close(); + + cmdList->Shutdown(); + delete cmdList; + delete rtv1; + delete rtv0; + texture1->Shutdown(); + delete texture1; + texture0->Shutdown(); + delete texture0; +} + +TEST_F(OpenGLTestFixture, CommandList_CopyResource_UsesActualTextureDimensions) { + constexpr uint32_t kWidth = 64; + constexpr uint32_t kHeight = 32; + + std::vector srcPixels(kWidth * kHeight * 4); + for (uint32_t y = 0; y < kHeight; ++y) { + for (uint32_t x = 0; x < kWidth; ++x) { + const size_t index = static_cast((y * kWidth + x) * 4); + srcPixels[index + 0] = static_cast(x * 3); + srcPixels[index + 1] = static_cast(y * 5); + srcPixels[index + 2] = static_cast((x + y) * 7); + srcPixels[index + 3] = 255; + } + } + + TextureDesc texDesc = {}; + texDesc.width = kWidth; + texDesc.height = kHeight; + texDesc.depth = 1; + texDesc.mipLevels = 1; + texDesc.arraySize = 1; + texDesc.format = static_cast(Format::R8G8B8A8_UNorm); + texDesc.textureType = static_cast(TextureType::Texture2D); + texDesc.sampleCount = 1; + texDesc.sampleQuality = 0; + + RHITexture* srcTexture = GetDevice()->CreateTexture(texDesc, srcPixels.data(), srcPixels.size(), kWidth * 4); + ASSERT_NE(srcTexture, nullptr); + RHITexture* dstTexture = GetDevice()->CreateTexture(texDesc); + ASSERT_NE(dstTexture, nullptr); + + RHIResourceView* srcView = GetDevice()->CreateShaderResourceView(srcTexture, {}); + RHIResourceView* dstView = GetDevice()->CreateShaderResourceView(dstTexture, {}); + ASSERT_NE(srcView, nullptr); + ASSERT_NE(dstView, nullptr); + + CommandListDesc cmdDesc = {}; + cmdDesc.commandListType = static_cast(CommandQueueType::Direct); + RHICommandList* cmdList = GetDevice()->CreateCommandList(cmdDesc); + ASSERT_NE(cmdList, nullptr); + + cmdList->Reset(); + cmdList->CopyResource(dstView, srcView); + glFinish(); + cmdList->Close(); + + std::vector dstPixels(kWidth * kHeight * 4, 0); + const GLuint dstTextureId = static_cast(dstView)->GetTexture(); + glBindTexture(GL_TEXTURE_2D, dstTextureId); + glGetTexImage(GL_TEXTURE_2D, 0, GL_RGBA, GL_UNSIGNED_BYTE, dstPixels.data()); + glBindTexture(GL_TEXTURE_2D, 0); + + EXPECT_EQ(dstPixels, srcPixels); + + cmdList->Shutdown(); + delete cmdList; + delete srcView; + delete dstView; + srcTexture->Shutdown(); + delete srcTexture; + dstTexture->Shutdown(); + delete dstTexture; +} + +TEST_F(OpenGLTestFixture, CommandList_SetVertexBuffers_InterleavedInputLayoutUsesPipelineLayout) { + ASSERT_TRUE(GetDevice()->MakeContextCurrent()); + + GraphicsPipelineDesc pipelineDesc = {}; + pipelineDesc.renderTargetFormats[0] = static_cast(Format::R8G8B8A8_UNorm); + + InputElementDesc position = {}; + position.semanticName = "POSITION"; + position.semanticIndex = 0; + position.format = static_cast(Format::R32G32B32A32_Float); + position.inputSlot = 0; + position.alignedByteOffset = 0; + pipelineDesc.inputLayout.elements.push_back(position); + + InputElementDesc color = {}; + color.semanticName = "COLOR"; + color.semanticIndex = 0; + color.format = static_cast(Format::R32G32B32A32_Float); + color.inputSlot = 0; + color.alignedByteOffset = sizeof(float) * 4; + pipelineDesc.inputLayout.elements.push_back(color); + + static const char* vertexSource = R"(#version 430 +layout(location = 0) in vec4 aPosition; +layout(location = 1) in vec4 aColor; +out vec4 vColor; +void main() { + gl_Position = aPosition; + vColor = aColor; +} +)"; + static const char* fragmentSource = R"(#version 430 +in vec4 vColor; +layout(location = 0) out vec4 fragColor; +void main() { + fragColor = vColor; +} +)"; + + pipelineDesc.vertexShader.source.assign(vertexSource, vertexSource + std::strlen(vertexSource)); + pipelineDesc.vertexShader.sourceLanguage = ShaderLanguage::GLSL; + pipelineDesc.vertexShader.profile = L"vs_4_30"; + + pipelineDesc.fragmentShader.source.assign(fragmentSource, fragmentSource + std::strlen(fragmentSource)); + pipelineDesc.fragmentShader.sourceLanguage = ShaderLanguage::GLSL; + pipelineDesc.fragmentShader.profile = L"fs_4_30"; + + RHIPipelineState* pipelineState = GetDevice()->CreatePipelineState(pipelineDesc); + ASSERT_NE(pipelineState, nullptr); + + BufferDesc bufferDesc = {}; + bufferDesc.size = sizeof(float) * 8 * 3; + bufferDesc.stride = sizeof(float) * 8; + bufferDesc.bufferType = static_cast(BufferType::Vertex); + + RHIBuffer* buffer = GetDevice()->CreateBuffer(bufferDesc); + ASSERT_NE(buffer, nullptr); + + ResourceViewDesc viewDesc = {}; + viewDesc.dimension = ResourceViewDimension::Buffer; + viewDesc.structureByteStride = bufferDesc.stride; + RHIResourceView* vbv = GetDevice()->CreateVertexBufferView(buffer, viewDesc); + ASSERT_NE(vbv, nullptr); + + CommandListDesc cmdDesc = {}; + cmdDesc.commandListType = static_cast(CommandQueueType::Direct); + RHICommandList* cmdList = GetDevice()->CreateCommandList(cmdDesc); + ASSERT_NE(cmdList, nullptr); + + RHIResourceView* views[] = { vbv }; + uint64_t offsets[] = { 0 }; + uint32_t strides[] = { bufferDesc.stride }; + + cmdList->Reset(); + cmdList->SetPipelineState(pipelineState); + cmdList->SetVertexBuffers(0, 1, views, offsets, strides); + + GLint enabled0 = 0; + GLint enabled1 = 0; + GLint size0 = 0; + GLint size1 = 0; + GLint stride0 = 0; + GLint stride1 = 0; + void* pointer0 = nullptr; + void* pointer1 = nullptr; + + glGetVertexAttribiv(0, GL_VERTEX_ATTRIB_ARRAY_ENABLED, &enabled0); + glGetVertexAttribiv(1, GL_VERTEX_ATTRIB_ARRAY_ENABLED, &enabled1); + glGetVertexAttribiv(0, GL_VERTEX_ATTRIB_ARRAY_SIZE, &size0); + glGetVertexAttribiv(1, GL_VERTEX_ATTRIB_ARRAY_SIZE, &size1); + glGetVertexAttribiv(0, GL_VERTEX_ATTRIB_ARRAY_STRIDE, &stride0); + glGetVertexAttribiv(1, GL_VERTEX_ATTRIB_ARRAY_STRIDE, &stride1); + glGetVertexAttribPointerv(0, GL_VERTEX_ATTRIB_ARRAY_POINTER, &pointer0); + glGetVertexAttribPointerv(1, GL_VERTEX_ATTRIB_ARRAY_POINTER, &pointer1); + + EXPECT_EQ(enabled0, GL_TRUE); + EXPECT_EQ(enabled1, GL_TRUE); + EXPECT_EQ(size0, 4); + EXPECT_EQ(size1, 4); + EXPECT_EQ(stride0, static_cast(bufferDesc.stride)); + EXPECT_EQ(stride1, static_cast(bufferDesc.stride)); + EXPECT_EQ(reinterpret_cast(pointer0), 0u); + EXPECT_EQ(reinterpret_cast(pointer1), sizeof(float) * 4u); + + cmdList->Close(); + + cmdList->Shutdown(); + delete cmdList; + vbv->Shutdown(); + delete vbv; + buffer->Shutdown(); + delete buffer; + pipelineState->Shutdown(); + delete pipelineState; +} + +TEST_F(OpenGLTestFixture, CommandList_SetComputeDescriptorSets_UsesSetAwareImageBindings) { + ASSERT_TRUE(GetDevice()->MakeContextCurrent()); + + const uint8_t initialPixel[4] = { 0, 0, 0, 0 }; + + TextureDesc textureDesc = {}; + textureDesc.width = 1; + textureDesc.height = 1; + textureDesc.depth = 1; + textureDesc.mipLevels = 1; + textureDesc.arraySize = 1; + textureDesc.format = static_cast(Format::R8G8B8A8_UNorm); + textureDesc.textureType = static_cast(TextureType::Texture2D); + textureDesc.sampleCount = 1; + + RHITexture* texture = GetDevice()->CreateTexture(textureDesc, initialPixel, sizeof(initialPixel), 4); + ASSERT_NE(texture, nullptr); + + ResourceViewDesc uavDesc = {}; + uavDesc.format = textureDesc.format; + uavDesc.dimension = ResourceViewDimension::Texture2D; + RHIResourceView* uav = GetDevice()->CreateUnorderedAccessView(texture, uavDesc); + ASSERT_NE(uav, nullptr); + + DescriptorPoolDesc poolDesc = {}; + poolDesc.type = DescriptorHeapType::CBV_SRV_UAV; + poolDesc.descriptorCount = 1; + poolDesc.shaderVisible = true; + RHIDescriptorPool* pool = GetDevice()->CreateDescriptorPool(poolDesc); + ASSERT_NE(pool, nullptr); + + DescriptorSetLayoutBinding reservedBinding = {}; + reservedBinding.binding = 0; + reservedBinding.type = static_cast(DescriptorType::UAV); + reservedBinding.count = 1; + + DescriptorSetLayoutBinding actualBinding = {}; + actualBinding.binding = 0; + actualBinding.type = static_cast(DescriptorType::UAV); + actualBinding.count = 1; + + DescriptorSetLayoutDesc reservedLayout = {}; + reservedLayout.bindings = &reservedBinding; + reservedLayout.bindingCount = 1; + + DescriptorSetLayoutDesc actualLayout = {}; + actualLayout.bindings = &actualBinding; + actualLayout.bindingCount = 1; + + DescriptorSetLayoutDesc setLayouts[2] = {}; + setLayouts[0] = reservedLayout; + setLayouts[1] = actualLayout; + + RHIPipelineLayoutDesc pipelineLayoutDesc = {}; + pipelineLayoutDesc.setLayouts = setLayouts; + pipelineLayoutDesc.setLayoutCount = 2; + RHIPipelineLayout* pipelineLayout = GetDevice()->CreatePipelineLayout(pipelineLayoutDesc); + ASSERT_NE(pipelineLayout, nullptr); + + RHIDescriptorSet* descriptorSet = pool->AllocateSet(actualLayout); + ASSERT_NE(descriptorSet, nullptr); + descriptorSet->Update(0, uav); + + GraphicsPipelineDesc pipelineDesc = {}; + RHIPipelineState* pipelineState = GetDevice()->CreatePipelineState(pipelineDesc); + ASSERT_NE(pipelineState, nullptr); + + ShaderCompileDesc shaderDesc = {}; + shaderDesc.sourceLanguage = ShaderLanguage::GLSL; + static const char* computeSource = R"( + #version 430 + layout(local_size_x = 1, local_size_y = 1, local_size_z = 1) in; + layout(binding = 1, rgba8) uniform writeonly image2D uImage; + void main() { + imageStore(uImage, ivec2(0, 0), vec4(1.0, 0.0, 0.0, 1.0)); + } + )"; + shaderDesc.source.assign(computeSource, computeSource + std::strlen(computeSource)); + shaderDesc.profile = L"cs_4_30"; + RHIShader* computeShader = GetDevice()->CreateShader(shaderDesc); + ASSERT_NE(computeShader, nullptr); + pipelineState->SetComputeShader(computeShader); + + CommandListDesc cmdDesc = {}; + cmdDesc.commandListType = static_cast(CommandQueueType::Direct); + RHICommandList* cmdList = GetDevice()->CreateCommandList(cmdDesc); + ASSERT_NE(cmdList, nullptr); + + glBindImageTexture(0, 0, 0, GL_FALSE, 0, GL_READ_WRITE, GL_RGBA8); + glBindImageTexture(1, 0, 0, GL_FALSE, 0, GL_READ_WRITE, GL_RGBA8); + + cmdList->Reset(); + cmdList->SetPipelineState(pipelineState); + RHIDescriptorSet* descriptorSets[] = { descriptorSet }; + cmdList->SetComputeDescriptorSets(1, 1, descriptorSets, pipelineLayout); + + GLint boundImageAtZero = -1; + GLint boundImageAtOne = -1; + glGetIntegeri_v(GL_IMAGE_BINDING_NAME, 0, &boundImageAtZero); + glGetIntegeri_v(GL_IMAGE_BINDING_NAME, 1, &boundImageAtOne); + EXPECT_EQ(boundImageAtZero, 0); + EXPECT_EQ( + static_cast(boundImageAtOne), + static_cast(reinterpret_cast(texture->GetNativeHandle()))); + + cmdList->Dispatch(1, 1, 1); + glMemoryBarrier(GL_ALL_BARRIER_BITS); + + uint8_t pixel[4] = {}; + glBindTexture(GL_TEXTURE_2D, static_cast(reinterpret_cast(texture->GetNativeHandle()))); + glGetTexImage(GL_TEXTURE_2D, 0, GL_RGBA, GL_UNSIGNED_BYTE, pixel); + glBindTexture(GL_TEXTURE_2D, 0); + + EXPECT_EQ(pixel[0], 255u); + EXPECT_EQ(pixel[1], 0u); + EXPECT_EQ(pixel[2], 0u); + EXPECT_EQ(pixel[3], 255u); + + cmdList->Close(); + + cmdList->Shutdown(); + delete cmdList; + computeShader->Shutdown(); + delete computeShader; + pipelineState->Shutdown(); + delete pipelineState; + descriptorSet->Shutdown(); + delete descriptorSet; + pipelineLayout->Shutdown(); + delete pipelineLayout; + pool->Shutdown(); + delete pool; + uav->Shutdown(); + delete uav; + texture->Shutdown(); + delete texture; +} + +TEST_F(OpenGLTestFixture, DescriptorSet_Update_UsesBindingNumber) { + ASSERT_TRUE(GetDevice()->MakeContextCurrent()); + + DescriptorPoolDesc poolDesc = {}; + poolDesc.type = DescriptorHeapType::CBV_SRV_UAV; + poolDesc.descriptorCount = 8; + poolDesc.shaderVisible = true; + + RHIDescriptorPool* pool = GetDevice()->CreateDescriptorPool(poolDesc); + ASSERT_NE(pool, nullptr); + + TextureDesc textureDesc = {}; + textureDesc.width = 1; + textureDesc.height = 1; + textureDesc.depth = 1; + textureDesc.mipLevels = 1; + textureDesc.arraySize = 1; + textureDesc.format = static_cast(Format::R8G8B8A8_UNorm); + textureDesc.textureType = static_cast(TextureType::Texture2D); + textureDesc.sampleCount = 1; + + const uint8_t pixel[4] = { 255, 255, 255, 255 }; + RHITexture* texture = GetDevice()->CreateTexture(textureDesc, pixel, sizeof(pixel), 4); + ASSERT_NE(texture, nullptr); + + ResourceViewDesc srvDesc = {}; + srvDesc.format = textureDesc.format; + srvDesc.dimension = ResourceViewDimension::Texture2D; + RHIResourceView* srv = GetDevice()->CreateShaderResourceView(texture, srvDesc); + ASSERT_NE(srv, nullptr); + + DescriptorSetLayoutBinding bindings[2] = {}; + bindings[0].binding = 3; + bindings[0].type = static_cast(DescriptorType::SRV); + bindings[0].count = 1; + bindings[1].binding = 7; + bindings[1].type = static_cast(DescriptorType::SRV); + bindings[1].count = 1; + + DescriptorSetLayoutDesc layoutDesc = {}; + layoutDesc.bindings = bindings; + layoutDesc.bindingCount = 2; + + RHIDescriptorSet* set = pool->AllocateSet(layoutDesc); + ASSERT_NE(set, nullptr); + + auto* openGLSet = static_cast(set); + const uint32_t untouchedUnit = openGLSet->GetBindingPoint(3); + const uint32_t updatedUnit = openGLSet->GetBindingPoint(7); + ASSERT_NE(untouchedUnit, updatedUnit); + + set->Update(7, srv); + set->Bind(); + + GLint updatedTexture = 0; + glActiveTexture(GL_TEXTURE0 + updatedUnit); + glGetIntegerv(GL_TEXTURE_BINDING_2D, &updatedTexture); + EXPECT_EQ(static_cast(updatedTexture), static_cast(reinterpret_cast(srv->GetNativeHandle()))); + + GLint untouchedTexture = 0; + glActiveTexture(GL_TEXTURE0 + untouchedUnit); + glGetIntegerv(GL_TEXTURE_BINDING_2D, &untouchedTexture); + EXPECT_EQ(untouchedTexture, 0); + + set->Unbind(); + + GLint unboundTexture = 0; + glActiveTexture(GL_TEXTURE0 + updatedUnit); + glGetIntegerv(GL_TEXTURE_BINDING_2D, &unboundTexture); + EXPECT_EQ(unboundTexture, 0); + + set->Shutdown(); + delete set; + srv->Shutdown(); + delete srv; + texture->Shutdown(); + delete texture; + pool->Shutdown(); + delete pool; +} + +TEST_F(OpenGLTestFixture, DescriptorSet_BindConstantBuffer_UsesBindingNumber) { + ASSERT_TRUE(GetDevice()->MakeContextCurrent()); + + DescriptorPoolDesc poolDesc = {}; + poolDesc.type = DescriptorHeapType::CBV_SRV_UAV; + poolDesc.descriptorCount = 1; + poolDesc.shaderVisible = false; + + RHIDescriptorPool* pool = GetDevice()->CreateDescriptorPool(poolDesc); + ASSERT_NE(pool, nullptr); + + DescriptorSetLayoutBinding binding = {}; + binding.binding = 3; + binding.type = static_cast(DescriptorType::CBV); + binding.count = 1; + + DescriptorSetLayoutDesc layoutDesc = {}; + layoutDesc.bindings = &binding; + layoutDesc.bindingCount = 1; + + RHIDescriptorSet* set = pool->AllocateSet(layoutDesc); + ASSERT_NE(set, nullptr); + + const float matrixData[16] = { + 1.0f, 0.0f, 0.0f, 0.0f, + 0.0f, 1.0f, 0.0f, 0.0f, + 0.0f, 0.0f, 1.0f, 0.0f, + 0.0f, 0.0f, 0.0f, 1.0f, + }; + set->WriteConstant(3, matrixData, sizeof(matrixData)); + set->Bind(); + + GLint boundBuffer = 0; + glGetIntegeri_v(GL_UNIFORM_BUFFER_BINDING, 3, &boundBuffer); + EXPECT_NE(boundBuffer, 0); + + set->Unbind(); + + GLint unboundBuffer = -1; + glGetIntegeri_v(GL_UNIFORM_BUFFER_BINDING, 3, &unboundBuffer); + EXPECT_EQ(unboundBuffer, 0); + + set->Shutdown(); + delete set; + pool->Shutdown(); + delete pool; +} + +TEST_F(OpenGLTestFixture, PipelineLayout_SeparatesOverlappingBindingsAcrossSetSlots) { + DescriptorSetLayoutBinding set0Bindings[4] = {}; + set0Bindings[0].binding = 0; + set0Bindings[0].type = static_cast(DescriptorType::CBV); + set0Bindings[0].count = 1; + set0Bindings[1].binding = 0; + set0Bindings[1].type = static_cast(DescriptorType::SRV); + set0Bindings[1].count = 1; + set0Bindings[2].binding = 0; + set0Bindings[2].type = static_cast(DescriptorType::UAV); + set0Bindings[2].count = 1; + set0Bindings[3].binding = 0; + set0Bindings[3].type = static_cast(DescriptorType::Sampler); + set0Bindings[3].count = 1; + + DescriptorSetLayoutBinding set1Bindings[4] = {}; + set1Bindings[0].binding = 0; + set1Bindings[0].type = static_cast(DescriptorType::CBV); + set1Bindings[0].count = 1; + set1Bindings[1].binding = 0; + set1Bindings[1].type = static_cast(DescriptorType::SRV); + set1Bindings[1].count = 1; + set1Bindings[2].binding = 0; + set1Bindings[2].type = static_cast(DescriptorType::UAV); + set1Bindings[2].count = 1; + set1Bindings[3].binding = 0; + set1Bindings[3].type = static_cast(DescriptorType::Sampler); + set1Bindings[3].count = 1; + + DescriptorSetLayoutDesc setLayouts[2] = {}; + setLayouts[0].bindings = set0Bindings; + setLayouts[0].bindingCount = 4; + setLayouts[1].bindings = set1Bindings; + setLayouts[1].bindingCount = 4; + + RHIPipelineLayoutDesc desc = {}; + desc.setLayouts = setLayouts; + desc.setLayoutCount = 2; + + RHIPipelineLayout* layout = GetDevice()->CreatePipelineLayout(desc); + ASSERT_NE(layout, nullptr); + + auto* openGLLayout = static_cast(layout); + EXPECT_TRUE(openGLLayout->UsesSetLayouts()); + EXPECT_EQ(openGLLayout->GetSetLayoutCount(), 2u); + EXPECT_TRUE(openGLLayout->HasConstantBufferBinding(0, 0)); + EXPECT_TRUE(openGLLayout->HasConstantBufferBinding(1, 0)); + EXPECT_EQ(openGLLayout->GetConstantBufferBindingPoint(0, 0), 0u); + EXPECT_EQ(openGLLayout->GetConstantBufferBindingPoint(1, 0), 1u); + EXPECT_EQ(openGLLayout->GetShaderResourceBindingPoint(0, 0), 0u); + EXPECT_EQ(openGLLayout->GetShaderResourceBindingPoint(1, 0), 1u); + EXPECT_EQ(openGLLayout->GetUnorderedAccessBindingPoint(0, 0), 0u); + EXPECT_EQ(openGLLayout->GetUnorderedAccessBindingPoint(1, 0), 1u); + EXPECT_EQ(openGLLayout->GetSamplerBindingPoint(0, 0), 0u); + EXPECT_EQ(openGLLayout->GetSamplerBindingPoint(1, 0), 1u); + + layout->Shutdown(); + delete layout; +} + +TEST_F(OpenGLTestFixture, Sampler_HonorsSamplerDesc) { + ASSERT_TRUE(GetDevice()->MakeContextCurrent()); + + SamplerDesc desc = {}; + desc.filter = static_cast(FilterMode::ComparisonAnisotropic); + desc.addressU = static_cast(TextureAddressMode::Clamp); + desc.addressV = static_cast(TextureAddressMode::Mirror); + desc.addressW = static_cast(TextureAddressMode::Border); + desc.maxAnisotropy = 8; + desc.comparisonFunc = static_cast(ComparisonFunc::GreaterEqual); + desc.minLod = 1.0f; + desc.maxLod = 4.0f; + + RHISampler* sampler = GetDevice()->CreateSampler(desc); + ASSERT_NE(sampler, nullptr); + + const GLuint samplerId = static_cast(sampler)->GetID(); + + GLint value = 0; + glGetSamplerParameteriv(samplerId, GL_TEXTURE_WRAP_S, &value); + EXPECT_EQ(value, GL_CLAMP_TO_EDGE); + glGetSamplerParameteriv(samplerId, GL_TEXTURE_WRAP_T, &value); + EXPECT_EQ(value, GL_MIRRORED_REPEAT); + glGetSamplerParameteriv(samplerId, GL_TEXTURE_WRAP_R, &value); + EXPECT_EQ(value, GL_CLAMP_TO_BORDER); + glGetSamplerParameteriv(samplerId, GL_TEXTURE_MIN_FILTER, &value); + EXPECT_EQ(value, GL_LINEAR_MIPMAP_LINEAR); + glGetSamplerParameteriv(samplerId, GL_TEXTURE_MAG_FILTER, &value); + EXPECT_EQ(value, GL_LINEAR); + glGetSamplerParameteriv(samplerId, GL_TEXTURE_COMPARE_MODE, &value); + EXPECT_EQ(value, GL_COMPARE_REF_TO_TEXTURE); + glGetSamplerParameteriv(samplerId, GL_TEXTURE_COMPARE_FUNC, &value); + EXPECT_EQ(value, GL_GEQUAL); + + GLfloat floatValue = 0.0f; + glGetSamplerParameterfv(samplerId, GL_TEXTURE_MAX_ANISOTROPY, &floatValue); + EXPECT_GE(floatValue, 8.0f); + glGetSamplerParameterfv(samplerId, GL_TEXTURE_MIN_LOD, &floatValue); + EXPECT_FLOAT_EQ(floatValue, 1.0f); + glGetSamplerParameterfv(samplerId, GL_TEXTURE_MAX_LOD, &floatValue); + EXPECT_FLOAT_EQ(floatValue, 4.0f); + + sampler->Shutdown(); + delete sampler; +} diff --git a/tests/RHI/unit/test_command_list.cpp b/tests/RHI/unit/test_command_list.cpp index d1af9d11..d988fdfa 100644 --- a/tests/RHI/unit/test_command_list.cpp +++ b/tests/RHI/unit/test_command_list.cpp @@ -6,10 +6,6 @@ #include "XCEngine/RHI/RHIPipelineState.h" #include "XCEngine/RHI/RHIRenderPass.h" #include "XCEngine/RHI/RHIFramebuffer.h" -#include "XCEngine/RHI/OpenGL/OpenGLDevice.h" -#include "XCEngine/RHI/OpenGL/OpenGLResourceView.h" -#include -#include using namespace XCEngine::RHI; @@ -397,145 +393,6 @@ TEST_P(RHITestFixture, CommandList_SetRenderTargets_WithRealViews) { delete texture; } -TEST_P(RHITestFixture, CommandList_SetRenderTargets_BindsColorAndDepthAttachmentsOnOpenGL) { - if (GetBackendType() != RHIType::OpenGL) { - GTEST_SKIP() << "OpenGL-specific framebuffer attachment verification"; - } - - TextureDesc colorDesc = {}; - colorDesc.width = 128; - colorDesc.height = 128; - colorDesc.format = static_cast(Format::R8G8B8A8_UNorm); - colorDesc.textureType = static_cast(TextureType::Texture2D); - - TextureDesc depthDesc = {}; - depthDesc.width = 128; - depthDesc.height = 128; - depthDesc.format = static_cast(Format::D24_UNorm_S8_UInt); - depthDesc.textureType = static_cast(TextureType::Texture2D); - - RHITexture* colorTexture = GetDevice()->CreateTexture(colorDesc); - RHITexture* depthTexture = GetDevice()->CreateTexture(depthDesc); - ASSERT_NE(colorTexture, nullptr); - ASSERT_NE(depthTexture, nullptr); - - ResourceViewDesc colorViewDesc = {}; - colorViewDesc.format = colorDesc.format; - RHIResourceView* rtv = GetDevice()->CreateRenderTargetView(colorTexture, colorViewDesc); - - ResourceViewDesc depthViewDesc = {}; - depthViewDesc.format = depthDesc.format; - RHIResourceView* dsv = GetDevice()->CreateDepthStencilView(depthTexture, depthViewDesc); - ASSERT_NE(rtv, nullptr); - ASSERT_NE(dsv, nullptr); - - CommandListDesc cmdDesc = {}; - cmdDesc.commandListType = static_cast(CommandQueueType::Direct); - RHICommandList* cmdList = GetDevice()->CreateCommandList(cmdDesc); - ASSERT_NE(cmdList, nullptr); - - cmdList->Reset(); - cmdList->SetRenderTargets(1, &rtv, dsv); - - GLint framebuffer = 0; - glGetIntegerv(GL_DRAW_FRAMEBUFFER_BINDING, &framebuffer); - EXPECT_NE(framebuffer, 0); - EXPECT_EQ(glCheckFramebufferStatus(GL_DRAW_FRAMEBUFFER), GL_FRAMEBUFFER_COMPLETE); - - GLint colorAttachment = 0; - glGetFramebufferAttachmentParameteriv( - GL_DRAW_FRAMEBUFFER, - GL_COLOR_ATTACHMENT0, - GL_FRAMEBUFFER_ATTACHMENT_OBJECT_NAME, - &colorAttachment); - EXPECT_EQ(static_cast(colorAttachment), static_cast(rtv)->GetTexture()); - - GLint depthAttachment = 0; - glGetFramebufferAttachmentParameteriv( - GL_DRAW_FRAMEBUFFER, - GL_DEPTH_ATTACHMENT, - GL_FRAMEBUFFER_ATTACHMENT_OBJECT_NAME, - &depthAttachment); - EXPECT_EQ(static_cast(depthAttachment), static_cast(dsv)->GetTexture()); - - cmdList->Close(); - - cmdList->Shutdown(); - delete cmdList; - delete dsv; - delete rtv; - depthTexture->Shutdown(); - delete depthTexture; - colorTexture->Shutdown(); - delete colorTexture; -} - -TEST_P(RHITestFixture, CommandList_SetRenderTargets_BindsMultipleColorAttachmentsOnOpenGL) { - if (GetBackendType() != RHIType::OpenGL) { - GTEST_SKIP() << "OpenGL-specific multiple render target verification"; - } - - TextureDesc texDesc = {}; - texDesc.width = 128; - texDesc.height = 128; - texDesc.format = static_cast(Format::R8G8B8A8_UNorm); - texDesc.textureType = static_cast(TextureType::Texture2D); - - RHITexture* texture0 = GetDevice()->CreateTexture(texDesc); - RHITexture* texture1 = GetDevice()->CreateTexture(texDesc); - ASSERT_NE(texture0, nullptr); - ASSERT_NE(texture1, nullptr); - - ResourceViewDesc viewDesc = {}; - viewDesc.format = texDesc.format; - RHIResourceView* rtv0 = GetDevice()->CreateRenderTargetView(texture0, viewDesc); - RHIResourceView* rtv1 = GetDevice()->CreateRenderTargetView(texture1, viewDesc); - ASSERT_NE(rtv0, nullptr); - ASSERT_NE(rtv1, nullptr); - - RHIResourceView* rtvs[] = { rtv0, rtv1 }; - - CommandListDesc cmdDesc = {}; - cmdDesc.commandListType = static_cast(CommandQueueType::Direct); - RHICommandList* cmdList = GetDevice()->CreateCommandList(cmdDesc); - ASSERT_NE(cmdList, nullptr); - - cmdList->Reset(); - cmdList->SetRenderTargets(2, rtvs, nullptr); - - GLint framebuffer = 0; - glGetIntegerv(GL_DRAW_FRAMEBUFFER_BINDING, &framebuffer); - EXPECT_NE(framebuffer, 0); - EXPECT_EQ(glCheckFramebufferStatus(GL_DRAW_FRAMEBUFFER), GL_FRAMEBUFFER_COMPLETE); - - GLint colorAttachment0 = 0; - glGetFramebufferAttachmentParameteriv( - GL_DRAW_FRAMEBUFFER, - GL_COLOR_ATTACHMENT0, - GL_FRAMEBUFFER_ATTACHMENT_OBJECT_NAME, - &colorAttachment0); - EXPECT_EQ(static_cast(colorAttachment0), static_cast(rtv0)->GetTexture()); - - GLint colorAttachment1 = 0; - glGetFramebufferAttachmentParameteriv( - GL_DRAW_FRAMEBUFFER, - GL_COLOR_ATTACHMENT1, - GL_FRAMEBUFFER_ATTACHMENT_OBJECT_NAME, - &colorAttachment1); - EXPECT_EQ(static_cast(colorAttachment1), static_cast(rtv1)->GetTexture()); - - cmdList->Close(); - - cmdList->Shutdown(); - delete cmdList; - delete rtv1; - delete rtv0; - texture1->Shutdown(); - delete texture1; - texture0->Shutdown(); - delete texture0; -} - TEST_P(RHITestFixture, CommandList_CopyResource_WithRealResources) { TextureDesc texDesc = {}; texDesc.width = 256; @@ -571,74 +428,6 @@ TEST_P(RHITestFixture, CommandList_CopyResource_WithRealResources) { delete dstTexture; } -TEST_P(RHITestFixture, CommandList_CopyResource_UsesActualTextureDimensionsOnOpenGL) { - if (GetBackendType() != RHIType::OpenGL) { - GTEST_SKIP() << "OpenGL-specific copy verification"; - } - - constexpr uint32_t kWidth = 64; - constexpr uint32_t kHeight = 32; - - std::vector srcPixels(kWidth * kHeight * 4); - for (uint32_t y = 0; y < kHeight; ++y) { - for (uint32_t x = 0; x < kWidth; ++x) { - const size_t index = static_cast((y * kWidth + x) * 4); - srcPixels[index + 0] = static_cast(x * 3); - srcPixels[index + 1] = static_cast(y * 5); - srcPixels[index + 2] = static_cast((x + y) * 7); - srcPixels[index + 3] = 255; - } - } - - TextureDesc texDesc = {}; - texDesc.width = kWidth; - texDesc.height = kHeight; - texDesc.depth = 1; - texDesc.mipLevels = 1; - texDesc.arraySize = 1; - texDesc.format = static_cast(Format::R8G8B8A8_UNorm); - texDesc.textureType = static_cast(TextureType::Texture2D); - texDesc.sampleCount = 1; - texDesc.sampleQuality = 0; - - RHITexture* srcTexture = GetDevice()->CreateTexture(texDesc, srcPixels.data(), srcPixels.size(), kWidth * 4); - ASSERT_NE(srcTexture, nullptr); - RHITexture* dstTexture = GetDevice()->CreateTexture(texDesc); - ASSERT_NE(dstTexture, nullptr); - - RHIResourceView* srcView = GetDevice()->CreateShaderResourceView(srcTexture, {}); - RHIResourceView* dstView = GetDevice()->CreateShaderResourceView(dstTexture, {}); - ASSERT_NE(srcView, nullptr); - ASSERT_NE(dstView, nullptr); - - CommandListDesc cmdDesc = {}; - cmdDesc.commandListType = static_cast(CommandQueueType::Direct); - RHICommandList* cmdList = GetDevice()->CreateCommandList(cmdDesc); - ASSERT_NE(cmdList, nullptr); - - cmdList->Reset(); - cmdList->CopyResource(dstView, srcView); - glFinish(); - cmdList->Close(); - - std::vector dstPixels(kWidth * kHeight * 4, 0); - const GLuint dstTextureId = static_cast(dstView)->GetTexture(); - glBindTexture(GL_TEXTURE_2D, dstTextureId); - glGetTexImage(GL_TEXTURE_2D, 0, GL_RGBA, GL_UNSIGNED_BYTE, dstPixels.data()); - glBindTexture(GL_TEXTURE_2D, 0); - - EXPECT_EQ(dstPixels, srcPixels); - - cmdList->Shutdown(); - delete cmdList; - delete srcView; - delete dstView; - srcTexture->Shutdown(); - delete srcTexture; - dstTexture->Shutdown(); - delete dstTexture; -} - TEST_P(RHITestFixture, CommandList_BeginEndRenderPass_Basic) { AttachmentDesc colorDesc = {}; colorDesc.format = Format::R8G8B8A8_UNorm; @@ -764,269 +553,3 @@ TEST_P(RHITestFixture, CommandList_SetShader) { shader->Shutdown(); delete shader; } - -TEST_P(RHITestFixture, CommandList_SetVertexBuffers_InterleavedInputLayoutUsesPipelineLayout) { - if (GetBackendType() != RHIType::OpenGL) { - GTEST_SKIP() << "OpenGL-specific vertex layout binding"; - } - - auto* openGLDevice = static_cast(GetDevice()); - ASSERT_NE(openGLDevice, nullptr); - ASSERT_TRUE(openGLDevice->MakeContextCurrent()); - - GraphicsPipelineDesc pipelineDesc = {}; - pipelineDesc.renderTargetFormats[0] = static_cast(Format::R8G8B8A8_UNorm); - - InputElementDesc position = {}; - position.semanticName = "POSITION"; - position.semanticIndex = 0; - position.format = static_cast(Format::R32G32B32A32_Float); - position.inputSlot = 0; - position.alignedByteOffset = 0; - pipelineDesc.inputLayout.elements.push_back(position); - - InputElementDesc color = {}; - color.semanticName = "COLOR"; - color.semanticIndex = 0; - color.format = static_cast(Format::R32G32B32A32_Float); - color.inputSlot = 0; - color.alignedByteOffset = sizeof(float) * 4; - pipelineDesc.inputLayout.elements.push_back(color); - - static const char* vertexSource = R"(#version 430 -layout(location = 0) in vec4 aPosition; -layout(location = 1) in vec4 aColor; -out vec4 vColor; -void main() { - gl_Position = aPosition; - vColor = aColor; -} -)"; - static const char* fragmentSource = R"(#version 430 -in vec4 vColor; -layout(location = 0) out vec4 fragColor; -void main() { - fragColor = vColor; -} -)"; - - pipelineDesc.vertexShader.source.assign(vertexSource, vertexSource + strlen(vertexSource)); - pipelineDesc.vertexShader.sourceLanguage = ShaderLanguage::GLSL; - pipelineDesc.vertexShader.profile = L"vs_4_30"; - - pipelineDesc.fragmentShader.source.assign(fragmentSource, fragmentSource + strlen(fragmentSource)); - pipelineDesc.fragmentShader.sourceLanguage = ShaderLanguage::GLSL; - pipelineDesc.fragmentShader.profile = L"fs_4_30"; - - RHIPipelineState* pipelineState = GetDevice()->CreatePipelineState(pipelineDesc); - ASSERT_NE(pipelineState, nullptr); - - BufferDesc bufferDesc = {}; - bufferDesc.size = sizeof(float) * 8 * 3; - bufferDesc.stride = sizeof(float) * 8; - bufferDesc.bufferType = static_cast(BufferType::Vertex); - - RHIBuffer* buffer = GetDevice()->CreateBuffer(bufferDesc); - ASSERT_NE(buffer, nullptr); - - ResourceViewDesc viewDesc = {}; - viewDesc.dimension = ResourceViewDimension::Buffer; - viewDesc.structureByteStride = bufferDesc.stride; - RHIResourceView* vbv = GetDevice()->CreateVertexBufferView(buffer, viewDesc); - ASSERT_NE(vbv, nullptr); - - CommandListDesc cmdDesc = {}; - cmdDesc.commandListType = static_cast(CommandQueueType::Direct); - RHICommandList* cmdList = GetDevice()->CreateCommandList(cmdDesc); - ASSERT_NE(cmdList, nullptr); - - RHIResourceView* views[] = { vbv }; - uint64_t offsets[] = { 0 }; - uint32_t strides[] = { bufferDesc.stride }; - - cmdList->Reset(); - cmdList->SetPipelineState(pipelineState); - cmdList->SetVertexBuffers(0, 1, views, offsets, strides); - - GLint enabled0 = 0; - GLint enabled1 = 0; - GLint size0 = 0; - GLint size1 = 0; - GLint stride0 = 0; - GLint stride1 = 0; - void* pointer0 = nullptr; - void* pointer1 = nullptr; - - glGetVertexAttribiv(0, GL_VERTEX_ATTRIB_ARRAY_ENABLED, &enabled0); - glGetVertexAttribiv(1, GL_VERTEX_ATTRIB_ARRAY_ENABLED, &enabled1); - glGetVertexAttribiv(0, GL_VERTEX_ATTRIB_ARRAY_SIZE, &size0); - glGetVertexAttribiv(1, GL_VERTEX_ATTRIB_ARRAY_SIZE, &size1); - glGetVertexAttribiv(0, GL_VERTEX_ATTRIB_ARRAY_STRIDE, &stride0); - glGetVertexAttribiv(1, GL_VERTEX_ATTRIB_ARRAY_STRIDE, &stride1); - glGetVertexAttribPointerv(0, GL_VERTEX_ATTRIB_ARRAY_POINTER, &pointer0); - glGetVertexAttribPointerv(1, GL_VERTEX_ATTRIB_ARRAY_POINTER, &pointer1); - - EXPECT_EQ(enabled0, GL_TRUE); - EXPECT_EQ(enabled1, GL_TRUE); - EXPECT_EQ(size0, 4); - EXPECT_EQ(size1, 4); - EXPECT_EQ(stride0, static_cast(bufferDesc.stride)); - EXPECT_EQ(stride1, static_cast(bufferDesc.stride)); - EXPECT_EQ(reinterpret_cast(pointer0), 0u); - EXPECT_EQ(reinterpret_cast(pointer1), sizeof(float) * 4u); - - cmdList->Close(); - - cmdList->Shutdown(); - delete cmdList; - vbv->Shutdown(); - delete vbv; - buffer->Shutdown(); - delete buffer; - pipelineState->Shutdown(); - delete pipelineState; -} - -TEST_P(RHITestFixture, CommandList_SetComputeDescriptorSets_UsesSetAwareImageBindingsOnOpenGL) { - if (GetBackendType() != RHIType::OpenGL) { - GTEST_SKIP() << "OpenGL-specific compute descriptor binding"; - } - - auto* openGLDevice = static_cast(GetDevice()); - ASSERT_NE(openGLDevice, nullptr); - ASSERT_TRUE(openGLDevice->MakeContextCurrent()); - - const uint8_t initialPixel[4] = { 0, 0, 0, 0 }; - - TextureDesc textureDesc = {}; - textureDesc.width = 1; - textureDesc.height = 1; - textureDesc.depth = 1; - textureDesc.mipLevels = 1; - textureDesc.arraySize = 1; - textureDesc.format = static_cast(Format::R8G8B8A8_UNorm); - textureDesc.textureType = static_cast(TextureType::Texture2D); - textureDesc.sampleCount = 1; - - RHITexture* texture = GetDevice()->CreateTexture(textureDesc, initialPixel, sizeof(initialPixel), 4); - ASSERT_NE(texture, nullptr); - - ResourceViewDesc uavDesc = {}; - uavDesc.format = textureDesc.format; - uavDesc.dimension = ResourceViewDimension::Texture2D; - RHIResourceView* uav = GetDevice()->CreateUnorderedAccessView(texture, uavDesc); - ASSERT_NE(uav, nullptr); - - DescriptorPoolDesc poolDesc = {}; - poolDesc.type = DescriptorHeapType::CBV_SRV_UAV; - poolDesc.descriptorCount = 1; - poolDesc.shaderVisible = true; - RHIDescriptorPool* pool = GetDevice()->CreateDescriptorPool(poolDesc); - ASSERT_NE(pool, nullptr); - - DescriptorSetLayoutBinding reservedBinding = {}; - reservedBinding.binding = 0; - reservedBinding.type = static_cast(DescriptorType::UAV); - reservedBinding.count = 1; - - DescriptorSetLayoutBinding actualBinding = {}; - actualBinding.binding = 0; - actualBinding.type = static_cast(DescriptorType::UAV); - actualBinding.count = 1; - - DescriptorSetLayoutDesc reservedLayout = {}; - reservedLayout.bindings = &reservedBinding; - reservedLayout.bindingCount = 1; - - DescriptorSetLayoutDesc actualLayout = {}; - actualLayout.bindings = &actualBinding; - actualLayout.bindingCount = 1; - - DescriptorSetLayoutDesc setLayouts[2] = {}; - setLayouts[0] = reservedLayout; - setLayouts[1] = actualLayout; - - RHIPipelineLayoutDesc pipelineLayoutDesc = {}; - pipelineLayoutDesc.setLayouts = setLayouts; - pipelineLayoutDesc.setLayoutCount = 2; - RHIPipelineLayout* pipelineLayout = GetDevice()->CreatePipelineLayout(pipelineLayoutDesc); - ASSERT_NE(pipelineLayout, nullptr); - - RHIDescriptorSet* descriptorSet = pool->AllocateSet(actualLayout); - ASSERT_NE(descriptorSet, nullptr); - descriptorSet->Update(0, uav); - - GraphicsPipelineDesc pipelineDesc = {}; - RHIPipelineState* pipelineState = GetDevice()->CreatePipelineState(pipelineDesc); - ASSERT_NE(pipelineState, nullptr); - - ShaderCompileDesc shaderDesc = {}; - shaderDesc.sourceLanguage = ShaderLanguage::GLSL; - static const char* computeSource = R"( - #version 430 - layout(local_size_x = 1, local_size_y = 1, local_size_z = 1) in; - layout(binding = 1, rgba8) uniform writeonly image2D uImage; - void main() { - imageStore(uImage, ivec2(0, 0), vec4(1.0, 0.0, 0.0, 1.0)); - } - )"; - shaderDesc.source.assign(computeSource, computeSource + strlen(computeSource)); - shaderDesc.profile = L"cs_4_30"; - RHIShader* computeShader = GetDevice()->CreateShader(shaderDesc); - ASSERT_NE(computeShader, nullptr); - pipelineState->SetComputeShader(computeShader); - - CommandListDesc cmdDesc = {}; - cmdDesc.commandListType = static_cast(CommandQueueType::Direct); - RHICommandList* cmdList = GetDevice()->CreateCommandList(cmdDesc); - ASSERT_NE(cmdList, nullptr); - - glBindImageTexture(0, 0, 0, GL_FALSE, 0, GL_READ_WRITE, GL_RGBA8); - glBindImageTexture(1, 0, 0, GL_FALSE, 0, GL_READ_WRITE, GL_RGBA8); - - cmdList->Reset(); - cmdList->SetPipelineState(pipelineState); - RHIDescriptorSet* descriptorSets[] = { descriptorSet }; - cmdList->SetComputeDescriptorSets(1, 1, descriptorSets, pipelineLayout); - - GLint boundImageAtZero = -1; - GLint boundImageAtOne = -1; - glGetIntegeri_v(GL_IMAGE_BINDING_NAME, 0, &boundImageAtZero); - glGetIntegeri_v(GL_IMAGE_BINDING_NAME, 1, &boundImageAtOne); - EXPECT_EQ(boundImageAtZero, 0); - EXPECT_EQ( - static_cast(boundImageAtOne), - static_cast(reinterpret_cast(texture->GetNativeHandle()))); - - cmdList->Dispatch(1, 1, 1); - glMemoryBarrier(GL_ALL_BARRIER_BITS); - - uint8_t pixel[4] = {}; - glBindTexture(GL_TEXTURE_2D, static_cast(reinterpret_cast(texture->GetNativeHandle()))); - glGetTexImage(GL_TEXTURE_2D, 0, GL_RGBA, GL_UNSIGNED_BYTE, pixel); - glBindTexture(GL_TEXTURE_2D, 0); - - EXPECT_EQ(pixel[0], 255u); - EXPECT_EQ(pixel[1], 0u); - EXPECT_EQ(pixel[2], 0u); - EXPECT_EQ(pixel[3], 255u); - - cmdList->Close(); - - cmdList->Shutdown(); - delete cmdList; - computeShader->Shutdown(); - delete computeShader; - pipelineState->Shutdown(); - delete pipelineState; - descriptorSet->Shutdown(); - delete descriptorSet; - pipelineLayout->Shutdown(); - delete pipelineLayout; - pool->Shutdown(); - delete pool; - uav->Shutdown(); - delete uav; - texture->Shutdown(); - delete texture; -} diff --git a/tests/RHI/unit/test_descriptor_set.cpp b/tests/RHI/unit/test_descriptor_set.cpp index 3e3395dc..03ad1547 100644 --- a/tests/RHI/unit/test_descriptor_set.cpp +++ b/tests/RHI/unit/test_descriptor_set.cpp @@ -1,15 +1,11 @@ #include "fixtures/RHITestFixture.h" #include "XCEngine/RHI/D3D12/D3D12DescriptorSet.h" -#include "XCEngine/RHI/OpenGL/OpenGLDescriptorSet.h" -#include "XCEngine/RHI/OpenGL/OpenGLDevice.h" #include "XCEngine/RHI/RHIDescriptorPool.h" #include "XCEngine/RHI/RHIDescriptorSet.h" #include "XCEngine/RHI/RHISampler.h" #include "XCEngine/RHI/RHIResourceView.h" #include "XCEngine/RHI/RHITexture.h" -#include - using namespace XCEngine::RHI; TEST_P(RHITestFixture, DescriptorSet_Allocate_Basic) { @@ -406,243 +402,3 @@ TEST_P(RHITestFixture, DescriptorSet_MultipleAllocations_AdvanceDescriptorOffset pool->Shutdown(); delete pool; } - -TEST_P(RHITestFixture, DescriptorSet_D3D12MixedBindings_AssignDescriptorIndicesByType) { - if (GetBackendType() != RHIType::D3D12) { - GTEST_SKIP() << "D3D12-specific descriptor index verification"; - } - - DescriptorPoolDesc poolDesc = {}; - poolDesc.type = DescriptorHeapType::CBV_SRV_UAV; - poolDesc.descriptorCount = 4; - poolDesc.shaderVisible = true; - - RHIDescriptorPool* pool = GetDevice()->CreateDescriptorPool(poolDesc); - ASSERT_NE(pool, nullptr); - - DescriptorSetLayoutBinding bindings[3] = {}; - bindings[0].binding = 2; - bindings[0].type = static_cast(DescriptorType::UAV); - bindings[0].count = 1; - bindings[1].binding = 0; - bindings[1].type = static_cast(DescriptorType::CBV); - bindings[1].count = 1; - bindings[2].binding = 1; - bindings[2].type = static_cast(DescriptorType::SRV); - bindings[2].count = 1; - - DescriptorSetLayoutDesc layoutDesc = {}; - layoutDesc.bindings = bindings; - layoutDesc.bindingCount = 3; - - RHIDescriptorSet* firstSet = pool->AllocateSet(layoutDesc); - RHIDescriptorSet* secondSet = pool->AllocateSet(layoutDesc); - ASSERT_NE(firstSet, nullptr); - ASSERT_NE(secondSet, nullptr); - - auto* firstD3D12Set = static_cast(firstSet); - auto* secondD3D12Set = static_cast(secondSet); - EXPECT_EQ(firstD3D12Set->GetCount(), 2u); - EXPECT_EQ(firstD3D12Set->GetDescriptorIndexForBinding(1), 0u); - EXPECT_EQ(firstD3D12Set->GetDescriptorIndexForBinding(2), 1u); - EXPECT_EQ(firstD3D12Set->GetDescriptorIndexForBinding(0), UINT32_MAX); - EXPECT_EQ(firstD3D12Set->GetOffset(), 0u); - EXPECT_EQ(secondD3D12Set->GetOffset(), 2u); - - firstSet->Shutdown(); - delete firstSet; - secondSet->Shutdown(); - delete secondSet; - pool->Shutdown(); - delete pool; -} - -TEST_P(RHITestFixture, DescriptorSet_D3D12MultipleConstantBuffersUploadIndependently) { - if (GetBackendType() != RHIType::D3D12) { - GTEST_SKIP() << "D3D12-specific constant buffer verification"; - } - - DescriptorPoolDesc poolDesc = {}; - poolDesc.type = DescriptorHeapType::CBV_SRV_UAV; - poolDesc.descriptorCount = 1; - poolDesc.shaderVisible = false; - - RHIDescriptorPool* pool = GetDevice()->CreateDescriptorPool(poolDesc); - ASSERT_NE(pool, nullptr); - - DescriptorSetLayoutBinding bindings[2] = {}; - bindings[0].binding = 0; - bindings[0].type = static_cast(DescriptorType::CBV); - bindings[0].count = 1; - bindings[1].binding = 1; - bindings[1].type = static_cast(DescriptorType::CBV); - bindings[1].count = 1; - - DescriptorSetLayoutDesc layoutDesc = {}; - layoutDesc.bindings = bindings; - layoutDesc.bindingCount = 2; - - RHIDescriptorSet* set = pool->AllocateSet(layoutDesc); - ASSERT_NE(set, nullptr); - - auto* d3d12Set = static_cast(set); - const float firstData[16] = { 1.0f, 0.0f, 0.0f, 0.0f }; - const float secondData[16] = { 2.0f, 0.0f, 0.0f, 0.0f }; - d3d12Set->WriteConstant(0, firstData, sizeof(firstData)); - d3d12Set->WriteConstant(1, secondData, sizeof(secondData)); - - ASSERT_TRUE(d3d12Set->UploadConstantBuffer(0)); - ASSERT_TRUE(d3d12Set->UploadConstantBuffer(1)); - - const D3D12_GPU_VIRTUAL_ADDRESS firstAddress = d3d12Set->GetConstantBufferGPUAddress(0); - const D3D12_GPU_VIRTUAL_ADDRESS secondAddress = d3d12Set->GetConstantBufferGPUAddress(1); - EXPECT_NE(firstAddress, 0u); - EXPECT_NE(secondAddress, 0u); - EXPECT_NE(firstAddress, secondAddress); - - set->Shutdown(); - delete set; - pool->Shutdown(); - delete pool; -} - -TEST_P(RHITestFixture, DescriptorSet_Update_UsesBindingNumberOnOpenGL) { - if (GetBackendType() != RHIType::OpenGL) { - GTEST_SKIP() << "OpenGL-specific descriptor binding verification"; - } - - auto* openGLDevice = static_cast(GetDevice()); - ASSERT_NE(openGLDevice, nullptr); - ASSERT_TRUE(openGLDevice->MakeContextCurrent()); - - DescriptorPoolDesc poolDesc = {}; - poolDesc.type = DescriptorHeapType::CBV_SRV_UAV; - poolDesc.descriptorCount = 8; - poolDesc.shaderVisible = true; - - RHIDescriptorPool* pool = GetDevice()->CreateDescriptorPool(poolDesc); - ASSERT_NE(pool, nullptr); - - TextureDesc textureDesc = {}; - textureDesc.width = 1; - textureDesc.height = 1; - textureDesc.depth = 1; - textureDesc.mipLevels = 1; - textureDesc.arraySize = 1; - textureDesc.format = static_cast(Format::R8G8B8A8_UNorm); - textureDesc.textureType = static_cast(TextureType::Texture2D); - textureDesc.sampleCount = 1; - - const uint8_t pixel[4] = { 255, 255, 255, 255 }; - RHITexture* texture = GetDevice()->CreateTexture(textureDesc, pixel, sizeof(pixel), 4); - ASSERT_NE(texture, nullptr); - - ResourceViewDesc srvDesc = {}; - srvDesc.format = textureDesc.format; - srvDesc.dimension = ResourceViewDimension::Texture2D; - RHIResourceView* srv = GetDevice()->CreateShaderResourceView(texture, srvDesc); - ASSERT_NE(srv, nullptr); - - DescriptorSetLayoutBinding bindings[2] = {}; - bindings[0].binding = 3; - bindings[0].type = static_cast(DescriptorType::SRV); - bindings[0].count = 1; - bindings[1].binding = 7; - bindings[1].type = static_cast(DescriptorType::SRV); - bindings[1].count = 1; - - DescriptorSetLayoutDesc layoutDesc = {}; - layoutDesc.bindings = bindings; - layoutDesc.bindingCount = 2; - - RHIDescriptorSet* set = pool->AllocateSet(layoutDesc); - ASSERT_NE(set, nullptr); - - auto* openGLSet = static_cast(set); - const uint32_t untouchedUnit = openGLSet->GetBindingPoint(3); - const uint32_t updatedUnit = openGLSet->GetBindingPoint(7); - ASSERT_NE(untouchedUnit, updatedUnit); - - set->Update(7, srv); - set->Bind(); - - GLint updatedTexture = 0; - glActiveTexture(GL_TEXTURE0 + updatedUnit); - glGetIntegerv(GL_TEXTURE_BINDING_2D, &updatedTexture); - EXPECT_EQ(static_cast(updatedTexture), static_cast(reinterpret_cast(srv->GetNativeHandle()))); - - GLint untouchedTexture = 0; - glActiveTexture(GL_TEXTURE0 + untouchedUnit); - glGetIntegerv(GL_TEXTURE_BINDING_2D, &untouchedTexture); - EXPECT_EQ(untouchedTexture, 0); - - set->Unbind(); - - GLint unboundTexture = 0; - glActiveTexture(GL_TEXTURE0 + updatedUnit); - glGetIntegerv(GL_TEXTURE_BINDING_2D, &unboundTexture); - EXPECT_EQ(unboundTexture, 0); - - set->Shutdown(); - delete set; - srv->Shutdown(); - delete srv; - texture->Shutdown(); - delete texture; - pool->Shutdown(); - delete pool; -} - -TEST_P(RHITestFixture, DescriptorSet_BindConstantBuffer_UsesBindingNumberOnOpenGL) { - if (GetBackendType() != RHIType::OpenGL) { - GTEST_SKIP() << "OpenGL-specific constant buffer binding verification"; - } - - auto* openGLDevice = static_cast(GetDevice()); - ASSERT_NE(openGLDevice, nullptr); - ASSERT_TRUE(openGLDevice->MakeContextCurrent()); - - DescriptorPoolDesc poolDesc = {}; - poolDesc.type = DescriptorHeapType::CBV_SRV_UAV; - poolDesc.descriptorCount = 1; - poolDesc.shaderVisible = false; - - RHIDescriptorPool* pool = GetDevice()->CreateDescriptorPool(poolDesc); - ASSERT_NE(pool, nullptr); - - DescriptorSetLayoutBinding binding = {}; - binding.binding = 3; - binding.type = static_cast(DescriptorType::CBV); - binding.count = 1; - - DescriptorSetLayoutDesc layoutDesc = {}; - layoutDesc.bindings = &binding; - layoutDesc.bindingCount = 1; - - RHIDescriptorSet* set = pool->AllocateSet(layoutDesc); - ASSERT_NE(set, nullptr); - - const float matrixData[16] = { - 1.0f, 0.0f, 0.0f, 0.0f, - 0.0f, 1.0f, 0.0f, 0.0f, - 0.0f, 0.0f, 1.0f, 0.0f, - 0.0f, 0.0f, 0.0f, 1.0f, - }; - set->WriteConstant(3, matrixData, sizeof(matrixData)); - set->Bind(); - - GLint boundBuffer = 0; - glGetIntegeri_v(GL_UNIFORM_BUFFER_BINDING, 3, &boundBuffer); - EXPECT_NE(boundBuffer, 0); - - set->Unbind(); - - GLint unboundBuffer = -1; - glGetIntegeri_v(GL_UNIFORM_BUFFER_BINDING, 3, &unboundBuffer); - EXPECT_EQ(unboundBuffer, 0); - - set->Shutdown(); - delete set; - pool->Shutdown(); - delete pool; -} diff --git a/tests/RHI/unit/test_device.cpp b/tests/RHI/unit/test_device.cpp index bdb19258..e2a630be 100644 --- a/tests/RHI/unit/test_device.cpp +++ b/tests/RHI/unit/test_device.cpp @@ -1,5 +1,4 @@ #include "fixtures/RHITestFixture.h" -#include "XCEngine/RHI/OpenGL/OpenGLDevice.h" using namespace XCEngine::RHI; @@ -20,39 +19,6 @@ TEST_P(RHITestFixture, Device_Initialize_Shutdown) { delete device; } -TEST_P(RHITestFixture, Device_Initialize_OpenGLUnifiedPath_CanCreateSwapChain) { - if (GetBackendType() != RHIType::OpenGL) { - GTEST_SKIP() << "OpenGL-specific unified initialization verification"; - } - - auto* device = new OpenGLDevice(); - ASSERT_NE(device, nullptr); - - RHIDeviceDesc deviceDesc = {}; - ASSERT_TRUE(device->Initialize(deviceDesc)); - - CommandQueueDesc queueDesc = {}; - queueDesc.queueType = static_cast(CommandQueueType::Direct); - RHICommandQueue* queue = device->CreateCommandQueue(queueDesc); - ASSERT_NE(queue, nullptr); - - SwapChainDesc swapDesc = {}; - swapDesc.windowHandle = GetWindowHandle(); - swapDesc.width = 320; - swapDesc.height = 180; - RHISwapChain* swapChain = device->CreateSwapChain(swapDesc, queue); - ASSERT_NE(swapChain, nullptr); - - swapChain->Present(0, 0); - - swapChain->Shutdown(); - delete swapChain; - queue->Shutdown(); - delete queue; - device->Shutdown(); - delete device; -} - TEST_P(RHITestFixture, Device_GetCapabilities_ReturnsValid) { const auto& caps = GetDevice()->GetCapabilities(); diff --git a/tests/RHI/unit/test_pipeline_layout.cpp b/tests/RHI/unit/test_pipeline_layout.cpp index b4474f25..db7dddc6 100644 --- a/tests/RHI/unit/test_pipeline_layout.cpp +++ b/tests/RHI/unit/test_pipeline_layout.cpp @@ -209,227 +209,3 @@ TEST_P(RHITestFixture, PipelineLayout_DeepCopiesSetLayoutsAndInfersCounts) { layout->Shutdown(); delete layout; } - -TEST_P(RHITestFixture, PipelineLayout_D3D12TracksDistinctBindingClasses) { - if (GetBackendType() != RHIType::D3D12) { - GTEST_SKIP() << "D3D12-specific root parameter verification"; - } - - RHIPipelineLayoutDesc desc = {}; - desc.constantBufferCount = 2; - desc.textureCount = 1; - desc.uavCount = 1; - desc.samplerCount = 1; - - RHIPipelineLayout* layout = GetDevice()->CreatePipelineLayout(desc); - ASSERT_NE(layout, nullptr); - - auto* d3d12Layout = static_cast(layout); - EXPECT_TRUE(d3d12Layout->HasConstantBufferBinding(0)); - EXPECT_TRUE(d3d12Layout->HasConstantBufferBinding(1)); - EXPECT_FALSE(d3d12Layout->HasConstantBufferBinding(2)); - - EXPECT_TRUE(d3d12Layout->HasShaderResourceTable()); - EXPECT_TRUE(d3d12Layout->HasUnorderedAccessTable()); - EXPECT_TRUE(d3d12Layout->HasSamplerTable()); - - EXPECT_NE( - d3d12Layout->GetConstantBufferRootParameterIndex(0), - d3d12Layout->GetConstantBufferRootParameterIndex(1)); - EXPECT_NE( - d3d12Layout->GetShaderResourceTableRootParameterIndex(), - d3d12Layout->GetUnorderedAccessTableRootParameterIndex()); - EXPECT_NE( - d3d12Layout->GetUnorderedAccessTableRootParameterIndex(), - d3d12Layout->GetSamplerTableRootParameterIndex()); - - layout->Shutdown(); - delete layout; -} - -TEST_P(RHITestFixture, PipelineLayout_D3D12InfersBindingClassesFromSetLayouts) { - if (GetBackendType() != RHIType::D3D12) { - GTEST_SKIP() << "D3D12-specific root parameter verification"; - } - - DescriptorSetLayoutBinding set0Bindings[1] = {}; - set0Bindings[0].binding = 0; - set0Bindings[0].type = static_cast(DescriptorType::CBV); - set0Bindings[0].count = 1; - - DescriptorSetLayoutBinding set1Bindings[1] = {}; - set1Bindings[0].binding = 0; - set1Bindings[0].type = static_cast(DescriptorType::SRV); - set1Bindings[0].count = 1; - - DescriptorSetLayoutBinding set2Bindings[1] = {}; - set2Bindings[0].binding = 0; - set2Bindings[0].type = static_cast(DescriptorType::UAV); - set2Bindings[0].count = 1; - - DescriptorSetLayoutBinding set3Bindings[1] = {}; - set3Bindings[0].binding = 0; - set3Bindings[0].type = static_cast(DescriptorType::Sampler); - set3Bindings[0].count = 1; - - DescriptorSetLayoutDesc setLayouts[4] = {}; - setLayouts[0].bindings = set0Bindings; - setLayouts[0].bindingCount = 1; - setLayouts[1].bindings = set1Bindings; - setLayouts[1].bindingCount = 1; - setLayouts[2].bindings = set2Bindings; - setLayouts[2].bindingCount = 1; - setLayouts[3].bindings = set3Bindings; - setLayouts[3].bindingCount = 1; - - RHIPipelineLayoutDesc desc = {}; - desc.setLayouts = setLayouts; - desc.setLayoutCount = 4; - - RHIPipelineLayout* layout = GetDevice()->CreatePipelineLayout(desc); - ASSERT_NE(layout, nullptr); - - auto* d3d12Layout = static_cast(layout); - EXPECT_TRUE(d3d12Layout->UsesSetLayouts()); - EXPECT_EQ(d3d12Layout->GetSetLayoutCount(), 4u); - EXPECT_TRUE(d3d12Layout->HasConstantBufferBinding(0, 0)); - EXPECT_TRUE(d3d12Layout->HasShaderResourceTable(1)); - EXPECT_TRUE(d3d12Layout->HasUnorderedAccessTable(2)); - EXPECT_TRUE(d3d12Layout->HasSamplerTable(3)); - EXPECT_EQ(d3d12Layout->GetDesc().constantBufferCount, 1u); - EXPECT_EQ(d3d12Layout->GetDesc().textureCount, 1u); - EXPECT_EQ(d3d12Layout->GetDesc().uavCount, 1u); - EXPECT_EQ(d3d12Layout->GetDesc().samplerCount, 1u); - - layout->Shutdown(); - delete layout; -} - -TEST_P(RHITestFixture, PipelineLayout_D3D12SeparatesOverlappingBindingsAcrossSetSlots) { - if (GetBackendType() != RHIType::D3D12) { - GTEST_SKIP() << "D3D12-specific root parameter verification"; - } - - DescriptorSetLayoutBinding set0Bindings[2] = {}; - set0Bindings[0].binding = 0; - set0Bindings[0].type = static_cast(DescriptorType::CBV); - set0Bindings[0].count = 1; - set0Bindings[1].binding = 0; - set0Bindings[1].type = static_cast(DescriptorType::SRV); - set0Bindings[1].count = 1; - - DescriptorSetLayoutBinding set1Bindings[2] = {}; - set1Bindings[0].binding = 0; - set1Bindings[0].type = static_cast(DescriptorType::CBV); - set1Bindings[0].count = 1; - set1Bindings[1].binding = 0; - set1Bindings[1].type = static_cast(DescriptorType::SRV); - set1Bindings[1].count = 1; - - DescriptorSetLayoutBinding set2Bindings[1] = {}; - set2Bindings[0].binding = 0; - set2Bindings[0].type = static_cast(DescriptorType::Sampler); - set2Bindings[0].count = 1; - - DescriptorSetLayoutDesc setLayouts[3] = {}; - setLayouts[0].bindings = set0Bindings; - setLayouts[0].bindingCount = 2; - setLayouts[1].bindings = set1Bindings; - setLayouts[1].bindingCount = 2; - setLayouts[2].bindings = set2Bindings; - setLayouts[2].bindingCount = 1; - - RHIPipelineLayoutDesc desc = {}; - desc.setLayouts = setLayouts; - desc.setLayoutCount = 3; - - RHIPipelineLayout* layout = GetDevice()->CreatePipelineLayout(desc); - ASSERT_NE(layout, nullptr); - - auto* d3d12Layout = static_cast(layout); - EXPECT_TRUE(d3d12Layout->UsesSetLayouts()); - EXPECT_TRUE(d3d12Layout->HasConstantBufferBinding(0, 0)); - EXPECT_TRUE(d3d12Layout->HasConstantBufferBinding(1, 0)); - EXPECT_FALSE(d3d12Layout->HasConstantBufferBinding(2, 0)); - EXPECT_NE( - d3d12Layout->GetConstantBufferRootParameterIndex(0, 0), - d3d12Layout->GetConstantBufferRootParameterIndex(1, 0)); - - EXPECT_TRUE(d3d12Layout->HasShaderResourceTable(0)); - EXPECT_TRUE(d3d12Layout->HasShaderResourceTable(1)); - EXPECT_FALSE(d3d12Layout->HasShaderResourceTable(2)); - EXPECT_NE( - d3d12Layout->GetShaderResourceTableRootParameterIndex(0), - d3d12Layout->GetShaderResourceTableRootParameterIndex(1)); - - EXPECT_FALSE(d3d12Layout->HasSamplerTable(0)); - EXPECT_FALSE(d3d12Layout->HasSamplerTable(1)); - EXPECT_TRUE(d3d12Layout->HasSamplerTable(2)); - - layout->Shutdown(); - delete layout; -} - -TEST_P(RHITestFixture, PipelineLayout_OpenGLSeparatesOverlappingBindingsAcrossSetSlots) { - if (GetBackendType() != RHIType::OpenGL) { - GTEST_SKIP() << "OpenGL-specific binding point verification"; - } - - DescriptorSetLayoutBinding set0Bindings[4] = {}; - set0Bindings[0].binding = 0; - set0Bindings[0].type = static_cast(DescriptorType::CBV); - set0Bindings[0].count = 1; - set0Bindings[1].binding = 0; - set0Bindings[1].type = static_cast(DescriptorType::SRV); - set0Bindings[1].count = 1; - set0Bindings[2].binding = 0; - set0Bindings[2].type = static_cast(DescriptorType::UAV); - set0Bindings[2].count = 1; - set0Bindings[3].binding = 0; - set0Bindings[3].type = static_cast(DescriptorType::Sampler); - set0Bindings[3].count = 1; - - DescriptorSetLayoutBinding set1Bindings[4] = {}; - set1Bindings[0].binding = 0; - set1Bindings[0].type = static_cast(DescriptorType::CBV); - set1Bindings[0].count = 1; - set1Bindings[1].binding = 0; - set1Bindings[1].type = static_cast(DescriptorType::SRV); - set1Bindings[1].count = 1; - set1Bindings[2].binding = 0; - set1Bindings[2].type = static_cast(DescriptorType::UAV); - set1Bindings[2].count = 1; - set1Bindings[3].binding = 0; - set1Bindings[3].type = static_cast(DescriptorType::Sampler); - set1Bindings[3].count = 1; - - DescriptorSetLayoutDesc setLayouts[2] = {}; - setLayouts[0].bindings = set0Bindings; - setLayouts[0].bindingCount = 4; - setLayouts[1].bindings = set1Bindings; - setLayouts[1].bindingCount = 4; - - RHIPipelineLayoutDesc desc = {}; - desc.setLayouts = setLayouts; - desc.setLayoutCount = 2; - - RHIPipelineLayout* layout = GetDevice()->CreatePipelineLayout(desc); - ASSERT_NE(layout, nullptr); - - auto* openGLLayout = static_cast(layout); - EXPECT_TRUE(openGLLayout->UsesSetLayouts()); - EXPECT_EQ(openGLLayout->GetSetLayoutCount(), 2u); - EXPECT_TRUE(openGLLayout->HasConstantBufferBinding(0, 0)); - EXPECT_TRUE(openGLLayout->HasConstantBufferBinding(1, 0)); - EXPECT_EQ(openGLLayout->GetConstantBufferBindingPoint(0, 0), 0u); - EXPECT_EQ(openGLLayout->GetConstantBufferBindingPoint(1, 0), 1u); - EXPECT_EQ(openGLLayout->GetShaderResourceBindingPoint(0, 0), 0u); - EXPECT_EQ(openGLLayout->GetShaderResourceBindingPoint(1, 0), 1u); - EXPECT_EQ(openGLLayout->GetUnorderedAccessBindingPoint(0, 0), 0u); - EXPECT_EQ(openGLLayout->GetUnorderedAccessBindingPoint(1, 0), 1u); - EXPECT_EQ(openGLLayout->GetSamplerBindingPoint(0, 0), 0u); - EXPECT_EQ(openGLLayout->GetSamplerBindingPoint(1, 0), 1u); - - layout->Shutdown(); - delete layout; -} diff --git a/tests/RHI/unit/test_sampler.cpp b/tests/RHI/unit/test_sampler.cpp index 281f5c8b..75ebdf01 100644 --- a/tests/RHI/unit/test_sampler.cpp +++ b/tests/RHI/unit/test_sampler.cpp @@ -1,7 +1,5 @@ #include "fixtures/RHITestFixture.h" #include "XCEngine/RHI/RHISampler.h" -#include "XCEngine/RHI/OpenGL/OpenGLSampler.h" -#include using namespace XCEngine::RHI; @@ -77,51 +75,3 @@ TEST_P(RHITestFixture, Sampler_GetNativeHandle) { sampler->Shutdown(); delete sampler; } - -TEST_P(RHITestFixture, Sampler_OpenGLHonorsSamplerDesc) { - if (GetBackendType() != RHIType::OpenGL) { - GTEST_SKIP() << "OpenGL-specific sampler parameter verification"; - } - - SamplerDesc desc = {}; - desc.filter = static_cast(FilterMode::ComparisonAnisotropic); - desc.addressU = static_cast(TextureAddressMode::Clamp); - desc.addressV = static_cast(TextureAddressMode::Mirror); - desc.addressW = static_cast(TextureAddressMode::Border); - desc.maxAnisotropy = 8; - desc.comparisonFunc = static_cast(ComparisonFunc::GreaterEqual); - desc.minLod = 1.0f; - desc.maxLod = 4.0f; - - RHISampler* sampler = GetDevice()->CreateSampler(desc); - ASSERT_NE(sampler, nullptr); - - const GLuint samplerId = static_cast(sampler)->GetID(); - - GLint value = 0; - glGetSamplerParameteriv(samplerId, GL_TEXTURE_WRAP_S, &value); - EXPECT_EQ(value, GL_CLAMP_TO_EDGE); - glGetSamplerParameteriv(samplerId, GL_TEXTURE_WRAP_T, &value); - EXPECT_EQ(value, GL_MIRRORED_REPEAT); - glGetSamplerParameteriv(samplerId, GL_TEXTURE_WRAP_R, &value); - EXPECT_EQ(value, GL_CLAMP_TO_BORDER); - glGetSamplerParameteriv(samplerId, GL_TEXTURE_MIN_FILTER, &value); - EXPECT_EQ(value, GL_LINEAR_MIPMAP_LINEAR); - glGetSamplerParameteriv(samplerId, GL_TEXTURE_MAG_FILTER, &value); - EXPECT_EQ(value, GL_LINEAR); - glGetSamplerParameteriv(samplerId, GL_TEXTURE_COMPARE_MODE, &value); - EXPECT_EQ(value, GL_COMPARE_REF_TO_TEXTURE); - glGetSamplerParameteriv(samplerId, GL_TEXTURE_COMPARE_FUNC, &value); - EXPECT_EQ(value, GL_GEQUAL); - - GLfloat floatValue = 0.0f; - glGetSamplerParameterfv(samplerId, GL_TEXTURE_MAX_ANISOTROPY, &floatValue); - EXPECT_GE(floatValue, 8.0f); - glGetSamplerParameterfv(samplerId, GL_TEXTURE_MIN_LOD, &floatValue); - EXPECT_FLOAT_EQ(floatValue, 1.0f); - glGetSamplerParameterfv(samplerId, GL_TEXTURE_MAX_LOD, &floatValue); - EXPECT_FLOAT_EQ(floatValue, 4.0f); - - sampler->Shutdown(); - delete sampler; -}