#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; }