Fix RHI texture binding and add pure quad test
This commit is contained in:
@@ -142,6 +142,7 @@ inline DXGI_FORMAT ToD3D12(Format format) {
|
|||||||
case Format::R32G32B32A32_Float: return DXGI_FORMAT_R32G32B32A32_FLOAT;
|
case Format::R32G32B32A32_Float: return DXGI_FORMAT_R32G32B32A32_FLOAT;
|
||||||
case Format::R16_Float: return DXGI_FORMAT_R16_FLOAT;
|
case Format::R16_Float: return DXGI_FORMAT_R16_FLOAT;
|
||||||
case Format::R32_Float: return DXGI_FORMAT_R32_FLOAT;
|
case Format::R32_Float: return DXGI_FORMAT_R32_FLOAT;
|
||||||
|
case Format::R32G32_Float: return DXGI_FORMAT_R32G32_FLOAT;
|
||||||
case Format::D16_UNorm: return DXGI_FORMAT_D16_UNORM;
|
case Format::D16_UNorm: return DXGI_FORMAT_D16_UNORM;
|
||||||
case Format::D24_UNorm_S8_UInt: return DXGI_FORMAT_D24_UNORM_S8_UINT;
|
case Format::D24_UNorm_S8_UInt: return DXGI_FORMAT_D24_UNORM_S8_UINT;
|
||||||
case Format::D32_Float: return DXGI_FORMAT_D32_FLOAT;
|
case Format::D32_Float: return DXGI_FORMAT_D32_FLOAT;
|
||||||
@@ -168,6 +169,7 @@ inline Format FromD3D12(DXGI_FORMAT format) {
|
|||||||
case DXGI_FORMAT_R32G32B32A32_FLOAT: return Format::R32G32B32A32_Float;
|
case DXGI_FORMAT_R32G32B32A32_FLOAT: return Format::R32G32B32A32_Float;
|
||||||
case DXGI_FORMAT_R16_FLOAT: return Format::R16_Float;
|
case DXGI_FORMAT_R16_FLOAT: return Format::R16_Float;
|
||||||
case DXGI_FORMAT_R32_FLOAT: return Format::R32_Float;
|
case DXGI_FORMAT_R32_FLOAT: return Format::R32_Float;
|
||||||
|
case DXGI_FORMAT_R32G32_FLOAT: return Format::R32G32_Float;
|
||||||
case DXGI_FORMAT_D16_UNORM: return Format::D16_UNorm;
|
case DXGI_FORMAT_D16_UNORM: return Format::D16_UNorm;
|
||||||
case DXGI_FORMAT_D24_UNORM_S8_UINT: return Format::D24_UNorm_S8_UInt;
|
case DXGI_FORMAT_D24_UNORM_S8_UINT: return Format::D24_UNorm_S8_UInt;
|
||||||
case DXGI_FORMAT_D32_FLOAT: return Format::D32_Float;
|
case DXGI_FORMAT_D32_FLOAT: return Format::D32_Float;
|
||||||
@@ -319,4 +321,4 @@ inline D3D12_COMMAND_LIST_TYPE ToD3D12(CommandQueueType type) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
} // namespace RHI
|
} // namespace RHI
|
||||||
} // namespace XCEngine
|
} // namespace XCEngine
|
||||||
|
|||||||
@@ -3,6 +3,7 @@
|
|||||||
#include <d3d12.h>
|
#include <d3d12.h>
|
||||||
#include <wrl/client.h>
|
#include <wrl/client.h>
|
||||||
#include <unordered_map>
|
#include <unordered_map>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
#include "../RHIPipelineLayout.h"
|
#include "../RHIPipelineLayout.h"
|
||||||
#include "D3D12RootSignature.h"
|
#include "D3D12RootSignature.h"
|
||||||
@@ -36,7 +37,8 @@ private:
|
|||||||
D3D12Device* m_device;
|
D3D12Device* m_device;
|
||||||
std::unordered_map<uint32_t, uint32_t> m_registerToRootIndex;
|
std::unordered_map<uint32_t, uint32_t> m_registerToRootIndex;
|
||||||
std::vector<D3D12_ROOT_PARAMETER> m_rootParameters;
|
std::vector<D3D12_ROOT_PARAMETER> m_rootParameters;
|
||||||
|
std::vector<D3D12_DESCRIPTOR_RANGE> m_descriptorRanges;
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace RHI
|
} // namespace RHI
|
||||||
} // namespace XCEngine
|
} // namespace XCEngine
|
||||||
|
|||||||
@@ -19,7 +19,7 @@ public:
|
|||||||
bool Initialize(ID3D12Device* device, const D3D12_SAMPLER_DESC& desc);
|
bool Initialize(ID3D12Device* device, const D3D12_SAMPLER_DESC& desc);
|
||||||
void Shutdown() override;
|
void Shutdown() override;
|
||||||
|
|
||||||
D3D12_SAMPLER_DESC GetDesc() const { return m_desc; }
|
const D3D12_SAMPLER_DESC& GetDesc() const { return m_desc; }
|
||||||
|
|
||||||
void* GetNativeHandle() override { return &m_desc; }
|
void* GetNativeHandle() override { return &m_desc; }
|
||||||
unsigned int GetID() override { return m_id; }
|
unsigned int GetID() override { return m_id; }
|
||||||
|
|||||||
@@ -20,7 +20,8 @@ public:
|
|||||||
bool Initialize(ID3D12Device* device, const D3D12_RESOURCE_DESC& desc, D3D12_RESOURCE_STATES initialState = D3D12_RESOURCE_STATE_COMMON);
|
bool Initialize(ID3D12Device* device, const D3D12_RESOURCE_DESC& desc, D3D12_RESOURCE_STATES initialState = D3D12_RESOURCE_STATE_COMMON);
|
||||||
bool InitializeFromExisting(ID3D12Resource* resource, bool ownsResource = false);
|
bool InitializeFromExisting(ID3D12Resource* resource, bool ownsResource = false);
|
||||||
bool InitializeFromData(ID3D12Device* device, ID3D12GraphicsCommandList* commandList,
|
bool InitializeFromData(ID3D12Device* device, ID3D12GraphicsCommandList* commandList,
|
||||||
const void* pixelData, uint32_t width, uint32_t height, DXGI_FORMAT format, uint32_t rowPitch = 0);
|
const void* pixelData, uint32_t width, uint32_t height, DXGI_FORMAT format, uint32_t rowPitch = 0,
|
||||||
|
ComPtr<ID3D12Resource>* uploadBuffer = nullptr);
|
||||||
bool InitializeDepthStencil(ID3D12Device* device, uint32_t width, uint32_t height, DXGI_FORMAT format = DXGI_FORMAT_D24_UNORM_S8_UINT);
|
bool InitializeDepthStencil(ID3D12Device* device, uint32_t width, uint32_t height, DXGI_FORMAT format = DXGI_FORMAT_D24_UNORM_S8_UINT);
|
||||||
void Shutdown() override;
|
void Shutdown() override;
|
||||||
|
|
||||||
|
|||||||
@@ -126,6 +126,9 @@ inline void ToOpenGLFormat(OpenGLFormat fmt, GLint& internalFormat, GLenum& glFo
|
|||||||
case OpenGLFormat::RG8:
|
case OpenGLFormat::RG8:
|
||||||
internalFormat = GL_RG8; glFormat = GL_RG; glType = GL_UNSIGNED_BYTE;
|
internalFormat = GL_RG8; glFormat = GL_RG; glType = GL_UNSIGNED_BYTE;
|
||||||
break;
|
break;
|
||||||
|
case OpenGLFormat::RG32F:
|
||||||
|
internalFormat = GL_RG32F; glFormat = GL_RG; glType = GL_FLOAT;
|
||||||
|
break;
|
||||||
case OpenGLFormat::RGBA8:
|
case OpenGLFormat::RGBA8:
|
||||||
internalFormat = GL_RGBA8; glFormat = GL_RGBA; glType = GL_UNSIGNED_BYTE;
|
internalFormat = GL_RGBA8; glFormat = GL_RGBA; glType = GL_UNSIGNED_BYTE;
|
||||||
break;
|
break;
|
||||||
|
|||||||
@@ -20,6 +20,7 @@ enum class OpenGLTextureType {
|
|||||||
enum class OpenGLFormat {
|
enum class OpenGLFormat {
|
||||||
R8,
|
R8,
|
||||||
RG8,
|
RG8,
|
||||||
|
RG32F,
|
||||||
RGBA8,
|
RGBA8,
|
||||||
RGBA16F,
|
RGBA16F,
|
||||||
RGBA32F,
|
RGBA32F,
|
||||||
@@ -32,6 +33,7 @@ enum class OpenGLFormat {
|
|||||||
enum class OpenGLInternalFormat {
|
enum class OpenGLInternalFormat {
|
||||||
R8 = 1,
|
R8 = 1,
|
||||||
RG8 = 2,
|
RG8 = 2,
|
||||||
|
RG32F = 13,
|
||||||
RGBA8 = 4,
|
RGBA8 = 4,
|
||||||
RGBA16F = 11,
|
RGBA16F = 11,
|
||||||
RGBA32F = 16,
|
RGBA32F = 16,
|
||||||
|
|||||||
@@ -314,7 +314,8 @@ enum class Format : uint32_t {
|
|||||||
BC6H_UF16,
|
BC6H_UF16,
|
||||||
BC7_UNorm,
|
BC7_UNorm,
|
||||||
R32G32B32A32_UInt,
|
R32G32B32A32_UInt,
|
||||||
R32_UInt
|
R32_UInt,
|
||||||
|
R32G32_Float
|
||||||
};
|
};
|
||||||
|
|
||||||
enum class ResourceStates : uint32_t {
|
enum class ResourceStates : uint32_t {
|
||||||
|
|||||||
@@ -37,6 +37,7 @@ bool D3D12DescriptorHeap::Initialize(ID3D12Device* device, DescriptorHeapType ty
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
m_device = device;
|
||||||
m_type = type;
|
m_type = type;
|
||||||
m_numDescriptors = numDescriptors;
|
m_numDescriptors = numDescriptors;
|
||||||
m_shaderVisible = shaderVisible;
|
m_shaderVisible = shaderVisible;
|
||||||
@@ -47,6 +48,7 @@ bool D3D12DescriptorHeap::Initialize(ID3D12Device* device, DescriptorHeapType ty
|
|||||||
}
|
}
|
||||||
|
|
||||||
void D3D12DescriptorHeap::Shutdown() {
|
void D3D12DescriptorHeap::Shutdown() {
|
||||||
|
m_device.Reset();
|
||||||
m_descriptorHeap.Reset();
|
m_descriptorHeap.Reset();
|
||||||
m_allocatedSets.clear();
|
m_allocatedSets.clear();
|
||||||
m_numDescriptors = 0;
|
m_numDescriptors = 0;
|
||||||
|
|||||||
@@ -74,6 +74,8 @@ uint32_t GetFormatBytesPerPixel(Format format) {
|
|||||||
return 8;
|
return 8;
|
||||||
case Format::R32_Float:
|
case Format::R32_Float:
|
||||||
return 4;
|
return 4;
|
||||||
|
case Format::R32G32_Float:
|
||||||
|
return 8;
|
||||||
case Format::R32G32B32A32_Float:
|
case Format::R32G32B32A32_Float:
|
||||||
return 16;
|
return 16;
|
||||||
default:
|
default:
|
||||||
@@ -390,6 +392,7 @@ RHITexture* D3D12Device::CreateTexture(const TextureDesc& desc, const void* init
|
|||||||
uploadCommandList.Reset();
|
uploadCommandList.Reset();
|
||||||
|
|
||||||
auto* texture = new D3D12Texture();
|
auto* texture = new D3D12Texture();
|
||||||
|
ComPtr<ID3D12Resource> uploadBuffer;
|
||||||
if (!texture->InitializeFromData(
|
if (!texture->InitializeFromData(
|
||||||
m_device.Get(),
|
m_device.Get(),
|
||||||
uploadCommandList.GetCommandList(),
|
uploadCommandList.GetCommandList(),
|
||||||
@@ -397,7 +400,8 @@ RHITexture* D3D12Device::CreateTexture(const TextureDesc& desc, const void* init
|
|||||||
desc.width,
|
desc.width,
|
||||||
desc.height,
|
desc.height,
|
||||||
ToD3D12(format),
|
ToD3D12(format),
|
||||||
resolvedRowPitch)) {
|
resolvedRowPitch,
|
||||||
|
&uploadBuffer)) {
|
||||||
delete texture;
|
delete texture;
|
||||||
uploadCommandList.Shutdown();
|
uploadCommandList.Shutdown();
|
||||||
uploadAllocator.Shutdown();
|
uploadAllocator.Shutdown();
|
||||||
@@ -411,6 +415,7 @@ RHITexture* D3D12Device::CreateTexture(const TextureDesc& desc, const void* init
|
|||||||
ID3D12CommandList* commandLists[] = { uploadCommandList.GetCommandList() };
|
ID3D12CommandList* commandLists[] = { uploadCommandList.GetCommandList() };
|
||||||
uploadQueue.ExecuteCommandListsInternal(1, commandLists);
|
uploadQueue.ExecuteCommandListsInternal(1, commandLists);
|
||||||
uploadQueue.WaitForIdle();
|
uploadQueue.WaitForIdle();
|
||||||
|
uploadBuffer.Reset();
|
||||||
|
|
||||||
uploadCommandList.Shutdown();
|
uploadCommandList.Shutdown();
|
||||||
uploadAllocator.Shutdown();
|
uploadAllocator.Shutdown();
|
||||||
@@ -442,13 +447,13 @@ RHIShader* D3D12Device::CreateShader(const ShaderCompileDesc& desc) {
|
|||||||
RHISampler* D3D12Device::CreateSampler(const SamplerDesc& desc) {
|
RHISampler* D3D12Device::CreateSampler(const SamplerDesc& desc) {
|
||||||
auto* sampler = new D3D12Sampler();
|
auto* sampler = new D3D12Sampler();
|
||||||
D3D12_SAMPLER_DESC d3d12Desc = {};
|
D3D12_SAMPLER_DESC d3d12Desc = {};
|
||||||
d3d12Desc.Filter = static_cast<D3D12_FILTER>(desc.filter);
|
d3d12Desc.Filter = ToD3D12(static_cast<FilterMode>(desc.filter));
|
||||||
d3d12Desc.AddressU = static_cast<D3D12_TEXTURE_ADDRESS_MODE>(desc.addressU);
|
d3d12Desc.AddressU = ToD3D12(static_cast<TextureAddressMode>(desc.addressU));
|
||||||
d3d12Desc.AddressV = static_cast<D3D12_TEXTURE_ADDRESS_MODE>(desc.addressV);
|
d3d12Desc.AddressV = ToD3D12(static_cast<TextureAddressMode>(desc.addressV));
|
||||||
d3d12Desc.AddressW = static_cast<D3D12_TEXTURE_ADDRESS_MODE>(desc.addressW);
|
d3d12Desc.AddressW = ToD3D12(static_cast<TextureAddressMode>(desc.addressW));
|
||||||
d3d12Desc.MipLODBias = desc.mipLodBias;
|
d3d12Desc.MipLODBias = desc.mipLodBias;
|
||||||
d3d12Desc.MaxAnisotropy = desc.maxAnisotropy;
|
d3d12Desc.MaxAnisotropy = desc.maxAnisotropy;
|
||||||
d3d12Desc.ComparisonFunc = static_cast<D3D12_COMPARISON_FUNC>(desc.comparisonFunc);
|
d3d12Desc.ComparisonFunc = ToD3D12(static_cast<ComparisonFunc>(desc.comparisonFunc));
|
||||||
d3d12Desc.BorderColor[0] = desc.borderColorR;
|
d3d12Desc.BorderColor[0] = desc.borderColorR;
|
||||||
d3d12Desc.BorderColor[1] = desc.borderColorG;
|
d3d12Desc.BorderColor[1] = desc.borderColorG;
|
||||||
d3d12Desc.BorderColor[2] = desc.borderColorB;
|
d3d12Desc.BorderColor[2] = desc.borderColorB;
|
||||||
@@ -735,7 +740,7 @@ RHIResourceView* D3D12Device::CreateShaderResourceView(RHITexture* texture, cons
|
|||||||
srvDesc.Shader4ComponentMapping = D3D12_DEFAULT_SHADER_4_COMPONENT_MAPPING;
|
srvDesc.Shader4ComponentMapping = D3D12_DEFAULT_SHADER_4_COMPONENT_MAPPING;
|
||||||
|
|
||||||
auto heap = std::make_unique<D3D12DescriptorHeap>();
|
auto heap = std::make_unique<D3D12DescriptorHeap>();
|
||||||
if (!heap->Initialize(m_device.Get(), DescriptorHeapType::CBV_SRV_UAV, 1, true)) {
|
if (!heap->Initialize(m_device.Get(), DescriptorHeapType::CBV_SRV_UAV, 1, false)) {
|
||||||
delete view;
|
delete view;
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
@@ -756,7 +761,7 @@ RHIResourceView* D3D12Device::CreateUnorderedAccessView(RHITexture* texture, con
|
|||||||
uavDesc.ViewDimension = D3D12_UAV_DIMENSION_TEXTURE2D;
|
uavDesc.ViewDimension = D3D12_UAV_DIMENSION_TEXTURE2D;
|
||||||
|
|
||||||
auto heap = std::make_unique<D3D12DescriptorHeap>();
|
auto heap = std::make_unique<D3D12DescriptorHeap>();
|
||||||
if (!heap->Initialize(m_device.Get(), DescriptorHeapType::CBV_SRV_UAV, 1, true)) {
|
if (!heap->Initialize(m_device.Get(), DescriptorHeapType::CBV_SRV_UAV, 1, false)) {
|
||||||
delete view;
|
delete view;
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -24,8 +24,20 @@ bool D3D12PipelineLayout::InitializeInternal(D3D12Device* device, const RHIPipel
|
|||||||
m_device = device;
|
m_device = device;
|
||||||
|
|
||||||
m_rootParameters.clear();
|
m_rootParameters.clear();
|
||||||
|
m_descriptorRanges.clear();
|
||||||
m_registerToRootIndex.clear();
|
m_registerToRootIndex.clear();
|
||||||
|
|
||||||
|
const uint32_t rootParameterCount =
|
||||||
|
(desc.constantBufferCount > 0 ? 1u : 0u) +
|
||||||
|
(desc.textureCount > 0 ? 1u : 0u) +
|
||||||
|
(desc.samplerCount > 0 ? 1u : 0u);
|
||||||
|
const uint32_t descriptorRangeCount =
|
||||||
|
(desc.textureCount > 0 ? 1u : 0u) +
|
||||||
|
(desc.samplerCount > 0 ? 1u : 0u);
|
||||||
|
|
||||||
|
m_rootParameters.reserve(rootParameterCount);
|
||||||
|
m_descriptorRanges.reserve(descriptorRangeCount);
|
||||||
|
|
||||||
uint32_t rootIndex = 0;
|
uint32_t rootIndex = 0;
|
||||||
|
|
||||||
if (desc.constantBufferCount > 0) {
|
if (desc.constantBufferCount > 0) {
|
||||||
@@ -39,9 +51,10 @@ bool D3D12PipelineLayout::InitializeInternal(D3D12Device* device, const RHIPipel
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (desc.textureCount > 0) {
|
if (desc.textureCount > 0) {
|
||||||
D3D12_DESCRIPTOR_RANGE range = D3D12RootSignature::CreateDescriptorRange(
|
m_descriptorRanges.push_back(D3D12RootSignature::CreateDescriptorRange(
|
||||||
D3D12_DESCRIPTOR_RANGE_TYPE_SRV, 0, desc.textureCount, 0);
|
D3D12_DESCRIPTOR_RANGE_TYPE_SRV, 0, desc.textureCount, 0));
|
||||||
D3D12_ROOT_PARAMETER param = D3D12RootSignature::CreateDescriptorTable(1, &range, ShaderVisibility::All);
|
D3D12_ROOT_PARAMETER param = D3D12RootSignature::CreateDescriptorTable(
|
||||||
|
1, &m_descriptorRanges.back(), ShaderVisibility::All);
|
||||||
m_rootParameters.push_back(param);
|
m_rootParameters.push_back(param);
|
||||||
for (uint32_t i = 0; i < desc.textureCount; ++i) {
|
for (uint32_t i = 0; i < desc.textureCount; ++i) {
|
||||||
m_registerToRootIndex[100 + i] = rootIndex;
|
m_registerToRootIndex[100 + i] = rootIndex;
|
||||||
@@ -50,9 +63,10 @@ bool D3D12PipelineLayout::InitializeInternal(D3D12Device* device, const RHIPipel
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (desc.samplerCount > 0) {
|
if (desc.samplerCount > 0) {
|
||||||
D3D12_DESCRIPTOR_RANGE range = D3D12RootSignature::CreateDescriptorRange(
|
m_descriptorRanges.push_back(D3D12RootSignature::CreateDescriptorRange(
|
||||||
D3D12_DESCRIPTOR_RANGE_TYPE_SAMPLER, 0, desc.samplerCount, 0);
|
D3D12_DESCRIPTOR_RANGE_TYPE_SAMPLER, 0, desc.samplerCount, 0));
|
||||||
D3D12_ROOT_PARAMETER param = D3D12RootSignature::CreateDescriptorTable(1, &range, ShaderVisibility::All);
|
D3D12_ROOT_PARAMETER param = D3D12RootSignature::CreateDescriptorTable(
|
||||||
|
1, &m_descriptorRanges.back(), ShaderVisibility::All);
|
||||||
m_rootParameters.push_back(param);
|
m_rootParameters.push_back(param);
|
||||||
for (uint32_t i = 0; i < desc.samplerCount; ++i) {
|
for (uint32_t i = 0; i < desc.samplerCount; ++i) {
|
||||||
m_registerToRootIndex[200 + i] = rootIndex;
|
m_registerToRootIndex[200 + i] = rootIndex;
|
||||||
@@ -99,6 +113,7 @@ bool D3D12PipelineLayout::InitializeInternal(D3D12Device* device, const RHIPipel
|
|||||||
void D3D12PipelineLayout::Shutdown() {
|
void D3D12PipelineLayout::Shutdown() {
|
||||||
m_rootSignature.Reset();
|
m_rootSignature.Reset();
|
||||||
m_rootParameters.clear();
|
m_rootParameters.clear();
|
||||||
|
m_descriptorRanges.clear();
|
||||||
m_registerToRootIndex.clear();
|
m_registerToRootIndex.clear();
|
||||||
m_device = nullptr;
|
m_device = nullptr;
|
||||||
}
|
}
|
||||||
@@ -116,4 +131,4 @@ bool D3D12PipelineLayout::HasRootParameter(uint32_t shaderRegister) const {
|
|||||||
}
|
}
|
||||||
|
|
||||||
} // namespace RHI
|
} // namespace RHI
|
||||||
} // namespace XCEngine
|
} // namespace XCEngine
|
||||||
|
|||||||
@@ -44,7 +44,8 @@ bool D3D12Texture::InitializeFromExisting(ID3D12Resource* resource, bool ownsRes
|
|||||||
}
|
}
|
||||||
|
|
||||||
bool D3D12Texture::InitializeFromData(ID3D12Device* device, ID3D12GraphicsCommandList* commandList,
|
bool D3D12Texture::InitializeFromData(ID3D12Device* device, ID3D12GraphicsCommandList* commandList,
|
||||||
const void* pixelData, uint32_t width, uint32_t height, DXGI_FORMAT format, uint32_t rowPitch) {
|
const void* pixelData, uint32_t width, uint32_t height, DXGI_FORMAT format, uint32_t rowPitch,
|
||||||
|
ComPtr<ID3D12Resource>* uploadBuffer) {
|
||||||
|
|
||||||
D3D12_RESOURCE_DESC textureDesc = {};
|
D3D12_RESOURCE_DESC textureDesc = {};
|
||||||
textureDesc.Dimension = D3D12_RESOURCE_DIMENSION_TEXTURE2D;
|
textureDesc.Dimension = D3D12_RESOURCE_DIMENSION_TEXTURE2D;
|
||||||
@@ -84,7 +85,7 @@ bool D3D12Texture::InitializeFromData(ID3D12Device* device, ID3D12GraphicsComman
|
|||||||
device->GetCopyableFootprints(&textureDesc, 0, 1, 0,
|
device->GetCopyableFootprints(&textureDesc, 0, 1, 0,
|
||||||
&subresourceFootprint, &rowUsed, &rowSizeInBytes, &memorySizeUsed);
|
&subresourceFootprint, &rowUsed, &rowSizeInBytes, &memorySizeUsed);
|
||||||
|
|
||||||
ID3D12Resource* tempBufferObject = nullptr;
|
ComPtr<ID3D12Resource> tempBufferObject;
|
||||||
D3D12_HEAP_PROPERTIES d3dTempHeapProperties = {};
|
D3D12_HEAP_PROPERTIES d3dTempHeapProperties = {};
|
||||||
d3dTempHeapProperties.Type = D3D12_HEAP_TYPE_UPLOAD;
|
d3dTempHeapProperties.Type = D3D12_HEAP_TYPE_UPLOAD;
|
||||||
|
|
||||||
@@ -107,7 +108,7 @@ bool D3D12Texture::InitializeFromData(ID3D12Device* device, ID3D12GraphicsComman
|
|||||||
&d3d12TempResourceDesc,
|
&d3d12TempResourceDesc,
|
||||||
D3D12_RESOURCE_STATE_GENERIC_READ,
|
D3D12_RESOURCE_STATE_GENERIC_READ,
|
||||||
nullptr,
|
nullptr,
|
||||||
IID_PPV_ARGS(&tempBufferObject)
|
IID_PPV_ARGS(tempBufferObject.GetAddressOf())
|
||||||
);
|
);
|
||||||
|
|
||||||
if (FAILED(hResult)) {
|
if (FAILED(hResult)) {
|
||||||
@@ -130,7 +131,7 @@ bool D3D12Texture::InitializeFromData(ID3D12Device* device, ID3D12GraphicsComman
|
|||||||
dst.SubresourceIndex = 0;
|
dst.SubresourceIndex = 0;
|
||||||
|
|
||||||
D3D12_TEXTURE_COPY_LOCATION src = {};
|
D3D12_TEXTURE_COPY_LOCATION src = {};
|
||||||
src.pResource = tempBufferObject;
|
src.pResource = tempBufferObject.Get();
|
||||||
src.Type = D3D12_TEXTURE_COPY_TYPE_PLACED_FOOTPRINT;
|
src.Type = D3D12_TEXTURE_COPY_TYPE_PLACED_FOOTPRINT;
|
||||||
src.PlacedFootprint = subresourceFootprint;
|
src.PlacedFootprint = subresourceFootprint;
|
||||||
commandList->CopyTextureRegion(&dst, 0, 0, 0, &src, nullptr);
|
commandList->CopyTextureRegion(&dst, 0, 0, 0, &src, nullptr);
|
||||||
@@ -145,7 +146,9 @@ bool D3D12Texture::InitializeFromData(ID3D12Device* device, ID3D12GraphicsComman
|
|||||||
commandList->ResourceBarrier(1, &barrier);
|
commandList->ResourceBarrier(1, &barrier);
|
||||||
m_state = ResourceStates::PixelShaderResource;
|
m_state = ResourceStates::PixelShaderResource;
|
||||||
|
|
||||||
tempBufferObject->Release();
|
if (uploadBuffer != nullptr) {
|
||||||
|
*uploadBuffer = tempBufferObject;
|
||||||
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -40,6 +40,9 @@ bool GetOpenGLVertexAttribFormat(Format format, OpenGLVertexAttribFormat& attrib
|
|||||||
case Format::R32_Float:
|
case Format::R32_Float:
|
||||||
attributeFormat = { 1, GL_FLOAT, GL_FALSE, false };
|
attributeFormat = { 1, GL_FLOAT, GL_FALSE, false };
|
||||||
return true;
|
return true;
|
||||||
|
case Format::R32G32_Float:
|
||||||
|
attributeFormat = { 2, GL_FLOAT, GL_FALSE, false };
|
||||||
|
return true;
|
||||||
case Format::R32G32B32A32_Float:
|
case Format::R32G32B32A32_Float:
|
||||||
attributeFormat = { 4, GL_FLOAT, GL_FALSE, false };
|
attributeFormat = { 4, GL_FLOAT, GL_FALSE, false };
|
||||||
return true;
|
return true;
|
||||||
|
|||||||
@@ -61,6 +61,29 @@ std::string SourceToString(const ShaderCompileDesc& desc) {
|
|||||||
return std::string(reinterpret_cast<const char*>(desc.source.data()), desc.source.size());
|
return std::string(reinterpret_cast<const char*>(desc.source.data()), desc.source.size());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
OpenGLFormat ToOpenGLTextureFormat(Format format) {
|
||||||
|
switch (format) {
|
||||||
|
case Format::R8_UNorm:
|
||||||
|
return OpenGLFormat::R8;
|
||||||
|
case Format::R8G8_UNorm:
|
||||||
|
return OpenGLFormat::RG8;
|
||||||
|
case Format::R32G32_Float:
|
||||||
|
return OpenGLFormat::RG32F;
|
||||||
|
case Format::R8G8B8A8_UNorm:
|
||||||
|
return OpenGLFormat::RGBA8;
|
||||||
|
case Format::R16G16B16A16_Float:
|
||||||
|
return OpenGLFormat::RGBA16F;
|
||||||
|
case Format::R32G32B32A32_Float:
|
||||||
|
return OpenGLFormat::RGBA32F;
|
||||||
|
case Format::D24_UNorm_S8_UInt:
|
||||||
|
return OpenGLFormat::Depth24Stencil8;
|
||||||
|
case Format::D32_Float:
|
||||||
|
return OpenGLFormat::Depth32F;
|
||||||
|
default:
|
||||||
|
return OpenGLFormat::RGBA8;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
} // namespace
|
} // namespace
|
||||||
|
|
||||||
OpenGLDevice::OpenGLDevice()
|
OpenGLDevice::OpenGLDevice()
|
||||||
@@ -338,19 +361,7 @@ RHITexture* OpenGLDevice::CreateTexture(const TextureDesc& desc) {
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
OpenGLFormat format = OpenGLFormat::RGBA8;
|
OpenGLFormat format = ToOpenGLTextureFormat(static_cast<Format>(desc.format));
|
||||||
switch (desc.format) {
|
|
||||||
case 1: format = OpenGLFormat::R8; break;
|
|
||||||
case 2: format = OpenGLFormat::RG8; break;
|
|
||||||
case 3: format = OpenGLFormat::RGBA8; break;
|
|
||||||
case 4: format = OpenGLFormat::RGBA16F; break;
|
|
||||||
case 5: format = OpenGLFormat::RGBA32F; break;
|
|
||||||
case 6: format = OpenGLFormat::RGBA16F; break;
|
|
||||||
case 7: format = OpenGLFormat::RGBA32F; break;
|
|
||||||
case 8: format = OpenGLFormat::Depth24Stencil8; break;
|
|
||||||
case 9: format = OpenGLFormat::Depth32F; break;
|
|
||||||
default: format = OpenGLFormat::RGBA8; break;
|
|
||||||
}
|
|
||||||
texture->Initialize(type, desc.width, desc.height, desc.depth, desc.mipLevels, format, nullptr);
|
texture->Initialize(type, desc.width, desc.height, desc.depth, desc.mipLevels, format, nullptr);
|
||||||
texture->SetFormat(static_cast<Format>(desc.format));
|
texture->SetFormat(static_cast<Format>(desc.format));
|
||||||
return texture;
|
return texture;
|
||||||
@@ -385,19 +396,7 @@ RHITexture* OpenGLDevice::CreateTexture(const TextureDesc& desc, const void* ini
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
OpenGLFormat format = OpenGLFormat::RGBA8;
|
OpenGLFormat format = ToOpenGLTextureFormat(static_cast<Format>(desc.format));
|
||||||
switch (desc.format) {
|
|
||||||
case 1: format = OpenGLFormat::R8; break;
|
|
||||||
case 2: format = OpenGLFormat::RG8; break;
|
|
||||||
case 3: format = OpenGLFormat::RGBA8; break;
|
|
||||||
case 4: format = OpenGLFormat::RGBA16F; break;
|
|
||||||
case 5: format = OpenGLFormat::RGBA32F; break;
|
|
||||||
case 6: format = OpenGLFormat::RGBA16F; break;
|
|
||||||
case 7: format = OpenGLFormat::RGBA32F; break;
|
|
||||||
case 8: format = OpenGLFormat::Depth24Stencil8; break;
|
|
||||||
case 9: format = OpenGLFormat::Depth32F; break;
|
|
||||||
default: format = OpenGLFormat::RGBA8; break;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!texture->Initialize(type, desc.width, desc.height, desc.depth, desc.mipLevels, format, initialData)) {
|
if (!texture->Initialize(type, desc.width, desc.height, desc.depth, desc.mipLevels, format, initialData)) {
|
||||||
delete texture;
|
delete texture;
|
||||||
|
|||||||
@@ -6,3 +6,4 @@ enable_testing()
|
|||||||
|
|
||||||
add_subdirectory(minimal)
|
add_subdirectory(minimal)
|
||||||
add_subdirectory(triangle)
|
add_subdirectory(triangle)
|
||||||
|
add_subdirectory(quad)
|
||||||
|
|||||||
59
tests/RHI/integration/quad/CMakeLists.txt
Normal file
59
tests/RHI/integration/quad/CMakeLists.txt
Normal file
@@ -0,0 +1,59 @@
|
|||||||
|
cmake_minimum_required(VERSION 3.15)
|
||||||
|
|
||||||
|
set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR})
|
||||||
|
|
||||||
|
project(rhi_integration_quad)
|
||||||
|
|
||||||
|
set(ENGINE_ROOT_DIR ${CMAKE_SOURCE_DIR}/engine)
|
||||||
|
set(PACKAGE_DIR ${CMAKE_SOURCE_DIR}/tests/opengl/package)
|
||||||
|
|
||||||
|
get_filename_component(PROJECT_ROOT_DIR ${CMAKE_CURRENT_SOURCE_DIR}/../../../.. ABSOLUTE)
|
||||||
|
|
||||||
|
add_executable(rhi_integration_quad
|
||||||
|
main.cpp
|
||||||
|
${CMAKE_CURRENT_SOURCE_DIR}/../fixtures/RHIIntegrationFixture.cpp
|
||||||
|
${PACKAGE_DIR}/src/glad.c
|
||||||
|
)
|
||||||
|
|
||||||
|
target_include_directories(rhi_integration_quad PRIVATE
|
||||||
|
${CMAKE_CURRENT_SOURCE_DIR}
|
||||||
|
${CMAKE_CURRENT_SOURCE_DIR}/../fixtures
|
||||||
|
${ENGINE_ROOT_DIR}/include
|
||||||
|
${PACKAGE_DIR}/include
|
||||||
|
${PROJECT_ROOT_DIR}/engine/src
|
||||||
|
)
|
||||||
|
|
||||||
|
target_link_libraries(rhi_integration_quad PRIVATE
|
||||||
|
d3d12
|
||||||
|
dxgi
|
||||||
|
d3dcompiler
|
||||||
|
winmm
|
||||||
|
opengl32
|
||||||
|
XCEngine
|
||||||
|
GTest::gtest
|
||||||
|
)
|
||||||
|
|
||||||
|
target_compile_definitions(rhi_integration_quad PRIVATE
|
||||||
|
UNICODE
|
||||||
|
_UNICODE
|
||||||
|
XCENGINE_SUPPORT_OPENGL
|
||||||
|
XCENGINE_SUPPORT_D3D12
|
||||||
|
)
|
||||||
|
|
||||||
|
add_custom_command(TARGET rhi_integration_quad POST_BUILD
|
||||||
|
COMMAND ${CMAKE_COMMAND} -E copy_directory
|
||||||
|
${CMAKE_CURRENT_SOURCE_DIR}/Res
|
||||||
|
$<TARGET_FILE_DIR:rhi_integration_quad>/Res
|
||||||
|
COMMAND ${CMAKE_COMMAND} -E copy_if_different
|
||||||
|
${CMAKE_SOURCE_DIR}/tests/RHI/integration/compare_ppm.py
|
||||||
|
$<TARGET_FILE_DIR:rhi_integration_quad>/
|
||||||
|
COMMAND ${CMAKE_COMMAND} -E copy_if_different
|
||||||
|
${CMAKE_CURRENT_SOURCE_DIR}/GT.ppm
|
||||||
|
$<TARGET_FILE_DIR:rhi_integration_quad>/GT.ppm
|
||||||
|
COMMAND ${CMAKE_COMMAND} -E copy_if_different
|
||||||
|
${ENGINE_ROOT_DIR}/third_party/renderdoc/renderdoc.dll
|
||||||
|
$<TARGET_FILE_DIR:rhi_integration_quad>/
|
||||||
|
)
|
||||||
|
|
||||||
|
include(GoogleTest)
|
||||||
|
gtest_discover_tests(rhi_integration_quad)
|
||||||
BIN
tests/RHI/integration/quad/GT.ppm
Normal file
BIN
tests/RHI/integration/quad/GT.ppm
Normal file
Binary file not shown.
BIN
tests/RHI/integration/quad/Res/Image/earth.png
Normal file
BIN
tests/RHI/integration/quad/Res/Image/earth.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 189 KiB |
521
tests/RHI/integration/quad/main.cpp
Normal file
521
tests/RHI/integration/quad/main.cpp
Normal file
@@ -0,0 +1,521 @@
|
|||||||
|
#include <windows.h>
|
||||||
|
#include <filesystem>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
#include <gtest/gtest.h>
|
||||||
|
#include <stb/stb_image.h>
|
||||||
|
|
||||||
|
#include "../fixtures/RHIIntegrationFixture.h"
|
||||||
|
#include "XCEngine/Debug/ConsoleLogSink.h"
|
||||||
|
#include "XCEngine/Debug/Logger.h"
|
||||||
|
#include "XCEngine/RHI/RHIBuffer.h"
|
||||||
|
#include "XCEngine/RHI/RHIDescriptorPool.h"
|
||||||
|
#include "XCEngine/RHI/RHIDescriptorSet.h"
|
||||||
|
#include "XCEngine/RHI/RHIPipelineLayout.h"
|
||||||
|
#include "XCEngine/RHI/RHIPipelineState.h"
|
||||||
|
#include "XCEngine/RHI/RHIResourceView.h"
|
||||||
|
#include "XCEngine/RHI/RHISampler.h"
|
||||||
|
#include "XCEngine/RHI/RHITexture.h"
|
||||||
|
|
||||||
|
using namespace XCEngine::Debug;
|
||||||
|
using namespace XCEngine::RHI;
|
||||||
|
using namespace XCEngine::RHI::Integration;
|
||||||
|
|
||||||
|
namespace {
|
||||||
|
|
||||||
|
struct Vertex {
|
||||||
|
float pos[4];
|
||||||
|
float uv[2];
|
||||||
|
};
|
||||||
|
|
||||||
|
constexpr Vertex kQuadVertices[] = {
|
||||||
|
{ { -0.5f, -0.5f, 0.0f, 1.0f }, { 0.0f, 1.0f } },
|
||||||
|
{ { -0.5f, 0.5f, 0.0f, 1.0f }, { 0.0f, 0.0f } },
|
||||||
|
{ { 0.5f, -0.5f, 0.0f, 1.0f }, { 1.0f, 1.0f } },
|
||||||
|
{ { 0.5f, 0.5f, 0.0f, 1.0f }, { 1.0f, 0.0f } },
|
||||||
|
};
|
||||||
|
|
||||||
|
constexpr uint32_t kQuadIndices[] = { 0, 1, 2, 2, 1, 3 };
|
||||||
|
|
||||||
|
std::filesystem::path GetExecutableDirectory() {
|
||||||
|
char exePath[MAX_PATH] = {};
|
||||||
|
const DWORD length = GetModuleFileNameA(nullptr, exePath, MAX_PATH);
|
||||||
|
if (length == 0 || length >= MAX_PATH) {
|
||||||
|
return std::filesystem::current_path();
|
||||||
|
}
|
||||||
|
|
||||||
|
return std::filesystem::path(exePath).parent_path();
|
||||||
|
}
|
||||||
|
|
||||||
|
std::filesystem::path ResolveRuntimePath(const char* relativePath) {
|
||||||
|
return GetExecutableDirectory() / relativePath;
|
||||||
|
}
|
||||||
|
|
||||||
|
const char kQuadHlsl[] = R"(
|
||||||
|
Texture2D gTexture : register(t0);
|
||||||
|
SamplerState gSampler : register(s0);
|
||||||
|
|
||||||
|
struct VSInput {
|
||||||
|
float4 position : POSITION;
|
||||||
|
float2 texcoord : TEXCOORD;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct PSInput {
|
||||||
|
float4 position : SV_POSITION;
|
||||||
|
float2 texcoord : TEXCOORD;
|
||||||
|
};
|
||||||
|
|
||||||
|
PSInput MainVS(VSInput input) {
|
||||||
|
PSInput output;
|
||||||
|
output.position = input.position;
|
||||||
|
output.texcoord = input.texcoord;
|
||||||
|
return output;
|
||||||
|
}
|
||||||
|
|
||||||
|
float4 MainPS(PSInput input) : SV_TARGET {
|
||||||
|
return gTexture.Sample(gSampler, input.texcoord);
|
||||||
|
}
|
||||||
|
)";
|
||||||
|
|
||||||
|
const char kQuadVertexShader[] = R"(#version 430
|
||||||
|
layout(location = 0) in vec4 aPosition;
|
||||||
|
layout(location = 1) in vec2 aTexCoord;
|
||||||
|
|
||||||
|
out vec2 vTexCoord;
|
||||||
|
|
||||||
|
void main() {
|
||||||
|
gl_Position = aPosition;
|
||||||
|
vTexCoord = aTexCoord;
|
||||||
|
}
|
||||||
|
)";
|
||||||
|
|
||||||
|
const char kQuadFragmentShader[] = R"(#version 430
|
||||||
|
layout(binding = 0) uniform sampler2D uTexture;
|
||||||
|
|
||||||
|
in vec2 vTexCoord;
|
||||||
|
|
||||||
|
layout(location = 0) out vec4 fragColor;
|
||||||
|
|
||||||
|
void main() {
|
||||||
|
fragColor = texture(uTexture, vTexCoord);
|
||||||
|
}
|
||||||
|
)";
|
||||||
|
|
||||||
|
const char* GetScreenshotFilename(RHIType type) {
|
||||||
|
return type == RHIType::D3D12 ? "quad_d3d12.ppm" : "quad_opengl.ppm";
|
||||||
|
}
|
||||||
|
|
||||||
|
RHITexture* LoadQuadTexture(RHIDevice* device) {
|
||||||
|
const std::filesystem::path texturePath = ResolveRuntimePath("Res/Image/earth.png");
|
||||||
|
const std::string texturePathString = texturePath.string();
|
||||||
|
|
||||||
|
stbi_set_flip_vertically_on_load(0);
|
||||||
|
|
||||||
|
int width = 0;
|
||||||
|
int height = 0;
|
||||||
|
int channels = 0;
|
||||||
|
stbi_uc* pixels = stbi_load(texturePathString.c_str(), &width, &height, &channels, STBI_rgb_alpha);
|
||||||
|
if (pixels == nullptr) {
|
||||||
|
Log("[TEST] Failed to load quad texture: %s", texturePathString.c_str());
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
TextureDesc textureDesc = {};
|
||||||
|
textureDesc.width = static_cast<uint32_t>(width);
|
||||||
|
textureDesc.height = static_cast<uint32_t>(height);
|
||||||
|
textureDesc.depth = 1;
|
||||||
|
textureDesc.mipLevels = 1;
|
||||||
|
textureDesc.arraySize = 1;
|
||||||
|
textureDesc.format = static_cast<uint32_t>(Format::R8G8B8A8_UNorm);
|
||||||
|
textureDesc.textureType = static_cast<uint32_t>(TextureType::Texture2D);
|
||||||
|
textureDesc.sampleCount = 1;
|
||||||
|
textureDesc.sampleQuality = 0;
|
||||||
|
textureDesc.flags = 0;
|
||||||
|
|
||||||
|
RHITexture* texture = device->CreateTexture(
|
||||||
|
textureDesc,
|
||||||
|
pixels,
|
||||||
|
static_cast<size_t>(width) * static_cast<size_t>(height) * 4,
|
||||||
|
static_cast<uint32_t>(width) * 4);
|
||||||
|
stbi_image_free(pixels);
|
||||||
|
return texture;
|
||||||
|
}
|
||||||
|
|
||||||
|
int GetComparisonThreshold(RHIType type) {
|
||||||
|
return type == RHIType::OpenGL ? 5 : 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
GraphicsPipelineDesc CreateQuadPipelineDesc(RHIType type, RHIPipelineLayout* pipelineLayout) {
|
||||||
|
GraphicsPipelineDesc desc = {};
|
||||||
|
desc.pipelineLayout = pipelineLayout;
|
||||||
|
desc.topologyType = static_cast<uint32_t>(PrimitiveTopologyType::Triangle);
|
||||||
|
desc.renderTargetFormats[0] = static_cast<uint32_t>(Format::R8G8B8A8_UNorm);
|
||||||
|
desc.depthStencilFormat = static_cast<uint32_t>(Format::Unknown);
|
||||||
|
desc.sampleCount = 1;
|
||||||
|
|
||||||
|
desc.rasterizerState.fillMode = static_cast<uint32_t>(FillMode::Solid);
|
||||||
|
desc.rasterizerState.cullMode = static_cast<uint32_t>(CullMode::None);
|
||||||
|
desc.rasterizerState.frontFace = static_cast<uint32_t>(FrontFace::CounterClockwise);
|
||||||
|
desc.rasterizerState.depthClipEnable = true;
|
||||||
|
|
||||||
|
desc.depthStencilState.depthTestEnable = false;
|
||||||
|
desc.depthStencilState.depthWriteEnable = false;
|
||||||
|
desc.depthStencilState.stencilEnable = false;
|
||||||
|
|
||||||
|
InputElementDesc position = {};
|
||||||
|
position.semanticName = "POSITION";
|
||||||
|
position.semanticIndex = 0;
|
||||||
|
position.format = static_cast<uint32_t>(Format::R32G32B32A32_Float);
|
||||||
|
position.inputSlot = 0;
|
||||||
|
position.alignedByteOffset = 0;
|
||||||
|
desc.inputLayout.elements.push_back(position);
|
||||||
|
|
||||||
|
InputElementDesc texcoord = {};
|
||||||
|
texcoord.semanticName = "TEXCOORD";
|
||||||
|
texcoord.semanticIndex = 0;
|
||||||
|
texcoord.format = static_cast<uint32_t>(Format::R32G32_Float);
|
||||||
|
texcoord.inputSlot = 0;
|
||||||
|
texcoord.alignedByteOffset = sizeof(float) * 4;
|
||||||
|
desc.inputLayout.elements.push_back(texcoord);
|
||||||
|
|
||||||
|
if (type == RHIType::D3D12) {
|
||||||
|
desc.vertexShader.source.assign(kQuadHlsl, kQuadHlsl + strlen(kQuadHlsl));
|
||||||
|
desc.vertexShader.sourceLanguage = ShaderLanguage::HLSL;
|
||||||
|
desc.vertexShader.entryPoint = L"MainVS";
|
||||||
|
desc.vertexShader.profile = L"vs_5_0";
|
||||||
|
|
||||||
|
desc.fragmentShader.source.assign(kQuadHlsl, kQuadHlsl + strlen(kQuadHlsl));
|
||||||
|
desc.fragmentShader.sourceLanguage = ShaderLanguage::HLSL;
|
||||||
|
desc.fragmentShader.entryPoint = L"MainPS";
|
||||||
|
desc.fragmentShader.profile = L"ps_5_0";
|
||||||
|
} else {
|
||||||
|
desc.vertexShader.source.assign(kQuadVertexShader, kQuadVertexShader + strlen(kQuadVertexShader));
|
||||||
|
desc.vertexShader.sourceLanguage = ShaderLanguage::GLSL;
|
||||||
|
desc.vertexShader.profile = L"vs_4_30";
|
||||||
|
|
||||||
|
desc.fragmentShader.source.assign(kQuadFragmentShader, kQuadFragmentShader + strlen(kQuadFragmentShader));
|
||||||
|
desc.fragmentShader.sourceLanguage = ShaderLanguage::GLSL;
|
||||||
|
desc.fragmentShader.profile = L"fs_4_30";
|
||||||
|
}
|
||||||
|
|
||||||
|
return desc;
|
||||||
|
}
|
||||||
|
|
||||||
|
class QuadTest : public RHIIntegrationFixture {
|
||||||
|
protected:
|
||||||
|
void SetUp() override;
|
||||||
|
void TearDown() override;
|
||||||
|
void RenderFrame() override;
|
||||||
|
|
||||||
|
private:
|
||||||
|
void InitializeQuadResources();
|
||||||
|
void ShutdownQuadResources();
|
||||||
|
|
||||||
|
RHIBuffer* mVertexBuffer = nullptr;
|
||||||
|
RHIResourceView* mVertexBufferView = nullptr;
|
||||||
|
RHIBuffer* mIndexBuffer = nullptr;
|
||||||
|
RHIResourceView* mIndexBufferView = nullptr;
|
||||||
|
RHITexture* mTexture = nullptr;
|
||||||
|
RHIResourceView* mTextureView = nullptr;
|
||||||
|
RHISampler* mSampler = nullptr;
|
||||||
|
RHIDescriptorPool* mTexturePool = nullptr;
|
||||||
|
RHIDescriptorSet* mTextureSet = nullptr;
|
||||||
|
RHIDescriptorPool* mSamplerPool = nullptr;
|
||||||
|
RHIDescriptorSet* mSamplerSet = nullptr;
|
||||||
|
RHIPipelineLayout* mPipelineLayout = nullptr;
|
||||||
|
RHIPipelineState* mPipelineState = nullptr;
|
||||||
|
};
|
||||||
|
|
||||||
|
void QuadTest::SetUp() {
|
||||||
|
RHIIntegrationFixture::SetUp();
|
||||||
|
InitializeQuadResources();
|
||||||
|
}
|
||||||
|
|
||||||
|
void QuadTest::TearDown() {
|
||||||
|
ShutdownQuadResources();
|
||||||
|
RHIIntegrationFixture::TearDown();
|
||||||
|
}
|
||||||
|
|
||||||
|
void QuadTest::InitializeQuadResources() {
|
||||||
|
BufferDesc vertexBufferDesc = {};
|
||||||
|
vertexBufferDesc.size = sizeof(kQuadVertices);
|
||||||
|
vertexBufferDesc.stride = sizeof(Vertex);
|
||||||
|
vertexBufferDesc.bufferType = static_cast<uint32_t>(BufferType::Vertex);
|
||||||
|
vertexBufferDesc.flags = 0;
|
||||||
|
|
||||||
|
mVertexBuffer = GetDevice()->CreateBuffer(vertexBufferDesc);
|
||||||
|
ASSERT_NE(mVertexBuffer, nullptr);
|
||||||
|
mVertexBuffer->SetData(kQuadVertices, sizeof(kQuadVertices));
|
||||||
|
mVertexBuffer->SetStride(sizeof(Vertex));
|
||||||
|
mVertexBuffer->SetBufferType(BufferType::Vertex);
|
||||||
|
|
||||||
|
ResourceViewDesc vertexViewDesc = {};
|
||||||
|
vertexViewDesc.dimension = ResourceViewDimension::Buffer;
|
||||||
|
vertexViewDesc.structureByteStride = sizeof(Vertex);
|
||||||
|
mVertexBufferView = GetDevice()->CreateVertexBufferView(mVertexBuffer, vertexViewDesc);
|
||||||
|
ASSERT_NE(mVertexBufferView, nullptr);
|
||||||
|
|
||||||
|
BufferDesc indexBufferDesc = {};
|
||||||
|
indexBufferDesc.size = sizeof(kQuadIndices);
|
||||||
|
indexBufferDesc.stride = sizeof(uint32_t);
|
||||||
|
indexBufferDesc.bufferType = static_cast<uint32_t>(BufferType::Index);
|
||||||
|
indexBufferDesc.flags = 0;
|
||||||
|
|
||||||
|
mIndexBuffer = GetDevice()->CreateBuffer(indexBufferDesc);
|
||||||
|
ASSERT_NE(mIndexBuffer, nullptr);
|
||||||
|
mIndexBuffer->SetData(kQuadIndices, sizeof(kQuadIndices));
|
||||||
|
mIndexBuffer->SetStride(sizeof(uint32_t));
|
||||||
|
mIndexBuffer->SetBufferType(BufferType::Index);
|
||||||
|
|
||||||
|
ResourceViewDesc indexViewDesc = {};
|
||||||
|
indexViewDesc.dimension = ResourceViewDimension::Buffer;
|
||||||
|
indexViewDesc.format = static_cast<uint32_t>(Format::R32_UInt);
|
||||||
|
mIndexBufferView = GetDevice()->CreateIndexBufferView(mIndexBuffer, indexViewDesc);
|
||||||
|
ASSERT_NE(mIndexBufferView, nullptr);
|
||||||
|
|
||||||
|
mTexture = LoadQuadTexture(GetDevice());
|
||||||
|
ASSERT_NE(mTexture, nullptr);
|
||||||
|
|
||||||
|
ResourceViewDesc textureViewDesc = {};
|
||||||
|
textureViewDesc.format = static_cast<uint32_t>(Format::R8G8B8A8_UNorm);
|
||||||
|
textureViewDesc.dimension = ResourceViewDimension::Texture2D;
|
||||||
|
textureViewDesc.mipLevel = 0;
|
||||||
|
mTextureView = GetDevice()->CreateShaderResourceView(mTexture, textureViewDesc);
|
||||||
|
ASSERT_NE(mTextureView, nullptr);
|
||||||
|
|
||||||
|
SamplerDesc samplerDesc = {};
|
||||||
|
samplerDesc.filter = static_cast<uint32_t>(FilterMode::Linear);
|
||||||
|
samplerDesc.addressU = static_cast<uint32_t>(TextureAddressMode::Clamp);
|
||||||
|
samplerDesc.addressV = static_cast<uint32_t>(TextureAddressMode::Clamp);
|
||||||
|
samplerDesc.addressW = static_cast<uint32_t>(TextureAddressMode::Clamp);
|
||||||
|
samplerDesc.mipLodBias = 0.0f;
|
||||||
|
samplerDesc.maxAnisotropy = 1;
|
||||||
|
samplerDesc.comparisonFunc = static_cast<uint32_t>(ComparisonFunc::Always);
|
||||||
|
samplerDesc.borderColorR = 0.0f;
|
||||||
|
samplerDesc.borderColorG = 0.0f;
|
||||||
|
samplerDesc.borderColorB = 0.0f;
|
||||||
|
samplerDesc.borderColorA = 0.0f;
|
||||||
|
samplerDesc.minLod = 0.0f;
|
||||||
|
samplerDesc.maxLod = 1000.0f;
|
||||||
|
mSampler = GetDevice()->CreateSampler(samplerDesc);
|
||||||
|
ASSERT_NE(mSampler, nullptr);
|
||||||
|
|
||||||
|
DescriptorPoolDesc texturePoolDesc = {};
|
||||||
|
texturePoolDesc.type = DescriptorHeapType::CBV_SRV_UAV;
|
||||||
|
texturePoolDesc.descriptorCount = 1;
|
||||||
|
texturePoolDesc.shaderVisible = true;
|
||||||
|
mTexturePool = GetDevice()->CreateDescriptorPool(texturePoolDesc);
|
||||||
|
ASSERT_NE(mTexturePool, nullptr);
|
||||||
|
|
||||||
|
DescriptorSetLayoutBinding textureBinding = {};
|
||||||
|
textureBinding.binding = 0;
|
||||||
|
textureBinding.type = static_cast<uint32_t>(DescriptorType::SRV);
|
||||||
|
textureBinding.count = 1;
|
||||||
|
|
||||||
|
DescriptorSetLayoutDesc textureLayoutDesc = {};
|
||||||
|
textureLayoutDesc.bindings = &textureBinding;
|
||||||
|
textureLayoutDesc.bindingCount = 1;
|
||||||
|
|
||||||
|
mTextureSet = mTexturePool->AllocateSet(textureLayoutDesc);
|
||||||
|
ASSERT_NE(mTextureSet, nullptr);
|
||||||
|
mTextureSet->Update(0, mTextureView);
|
||||||
|
|
||||||
|
DescriptorPoolDesc samplerPoolDesc = {};
|
||||||
|
samplerPoolDesc.type = DescriptorHeapType::Sampler;
|
||||||
|
samplerPoolDesc.descriptorCount = 1;
|
||||||
|
samplerPoolDesc.shaderVisible = true;
|
||||||
|
mSamplerPool = GetDevice()->CreateDescriptorPool(samplerPoolDesc);
|
||||||
|
ASSERT_NE(mSamplerPool, nullptr);
|
||||||
|
|
||||||
|
DescriptorSetLayoutBinding samplerBinding = {};
|
||||||
|
samplerBinding.binding = 0;
|
||||||
|
samplerBinding.type = static_cast<uint32_t>(DescriptorType::Sampler);
|
||||||
|
samplerBinding.count = 1;
|
||||||
|
|
||||||
|
DescriptorSetLayoutDesc samplerLayoutDesc = {};
|
||||||
|
samplerLayoutDesc.bindings = &samplerBinding;
|
||||||
|
samplerLayoutDesc.bindingCount = 1;
|
||||||
|
|
||||||
|
mSamplerSet = mSamplerPool->AllocateSet(samplerLayoutDesc);
|
||||||
|
ASSERT_NE(mSamplerSet, nullptr);
|
||||||
|
mSamplerSet->UpdateSampler(0, mSampler);
|
||||||
|
|
||||||
|
RHIPipelineLayoutDesc pipelineLayoutDesc = {};
|
||||||
|
pipelineLayoutDesc.textureCount = 1;
|
||||||
|
pipelineLayoutDesc.samplerCount = 1;
|
||||||
|
mPipelineLayout = GetDevice()->CreatePipelineLayout(pipelineLayoutDesc);
|
||||||
|
ASSERT_NE(mPipelineLayout, nullptr);
|
||||||
|
|
||||||
|
GraphicsPipelineDesc pipelineDesc = CreateQuadPipelineDesc(GetBackendType(), mPipelineLayout);
|
||||||
|
mPipelineState = GetDevice()->CreatePipelineState(pipelineDesc);
|
||||||
|
ASSERT_NE(mPipelineState, nullptr);
|
||||||
|
ASSERT_TRUE(mPipelineState->IsValid());
|
||||||
|
|
||||||
|
Log("[TEST] Quad resources initialized for backend %d", static_cast<int>(GetBackendType()));
|
||||||
|
}
|
||||||
|
|
||||||
|
void QuadTest::ShutdownQuadResources() {
|
||||||
|
if (mPipelineState != nullptr) {
|
||||||
|
mPipelineState->Shutdown();
|
||||||
|
delete mPipelineState;
|
||||||
|
mPipelineState = nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (mPipelineLayout != nullptr) {
|
||||||
|
mPipelineLayout->Shutdown();
|
||||||
|
delete mPipelineLayout;
|
||||||
|
mPipelineLayout = nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (mTextureSet != nullptr) {
|
||||||
|
mTextureSet->Shutdown();
|
||||||
|
delete mTextureSet;
|
||||||
|
mTextureSet = nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (mSamplerSet != nullptr) {
|
||||||
|
mSamplerSet->Shutdown();
|
||||||
|
delete mSamplerSet;
|
||||||
|
mSamplerSet = nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (mTexturePool != nullptr) {
|
||||||
|
mTexturePool->Shutdown();
|
||||||
|
delete mTexturePool;
|
||||||
|
mTexturePool = nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (mSamplerPool != nullptr) {
|
||||||
|
mSamplerPool->Shutdown();
|
||||||
|
delete mSamplerPool;
|
||||||
|
mSamplerPool = nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (mSampler != nullptr) {
|
||||||
|
mSampler->Shutdown();
|
||||||
|
delete mSampler;
|
||||||
|
mSampler = nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (mTextureView != nullptr) {
|
||||||
|
mTextureView->Shutdown();
|
||||||
|
delete mTextureView;
|
||||||
|
mTextureView = nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (mTexture != nullptr) {
|
||||||
|
mTexture->Shutdown();
|
||||||
|
delete mTexture;
|
||||||
|
mTexture = nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (mVertexBufferView != nullptr) {
|
||||||
|
mVertexBufferView->Shutdown();
|
||||||
|
delete mVertexBufferView;
|
||||||
|
mVertexBufferView = nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (mIndexBufferView != nullptr) {
|
||||||
|
mIndexBufferView->Shutdown();
|
||||||
|
delete mIndexBufferView;
|
||||||
|
mIndexBufferView = nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (mVertexBuffer != nullptr) {
|
||||||
|
mVertexBuffer->Shutdown();
|
||||||
|
delete mVertexBuffer;
|
||||||
|
mVertexBuffer = nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (mIndexBuffer != nullptr) {
|
||||||
|
mIndexBuffer->Shutdown();
|
||||||
|
delete mIndexBuffer;
|
||||||
|
mIndexBuffer = nullptr;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void QuadTest::RenderFrame() {
|
||||||
|
ASSERT_NE(mPipelineState, nullptr);
|
||||||
|
ASSERT_NE(mVertexBufferView, nullptr);
|
||||||
|
ASSERT_NE(mIndexBufferView, nullptr);
|
||||||
|
ASSERT_NE(mTextureSet, nullptr);
|
||||||
|
ASSERT_NE(mSamplerSet, nullptr);
|
||||||
|
ASSERT_NE(mPipelineLayout, nullptr);
|
||||||
|
|
||||||
|
RHICommandList* cmdList = GetCommandList();
|
||||||
|
RHICommandQueue* cmdQueue = GetCommandQueue();
|
||||||
|
ASSERT_NE(cmdList, nullptr);
|
||||||
|
ASSERT_NE(cmdQueue, nullptr);
|
||||||
|
|
||||||
|
cmdList->Reset();
|
||||||
|
SetRenderTargetForClear();
|
||||||
|
|
||||||
|
Viewport viewport = { 0.0f, 0.0f, 1280.0f, 720.0f, 0.0f, 1.0f };
|
||||||
|
Rect scissorRect = { 0, 0, 1280, 720 };
|
||||||
|
cmdList->SetViewport(viewport);
|
||||||
|
cmdList->SetScissorRect(scissorRect);
|
||||||
|
cmdList->Clear(0.0f, 0.0f, 1.0f, 1.0f, 1);
|
||||||
|
|
||||||
|
cmdList->SetPipelineState(mPipelineState);
|
||||||
|
RHIDescriptorSet* descriptorSets[] = { mTextureSet, mSamplerSet };
|
||||||
|
cmdList->SetGraphicsDescriptorSets(0, 2, descriptorSets, mPipelineLayout);
|
||||||
|
cmdList->SetPrimitiveTopology(PrimitiveTopology::TriangleList);
|
||||||
|
|
||||||
|
RHIResourceView* vertexBuffers[] = { mVertexBufferView };
|
||||||
|
uint64_t offsets[] = { 0 };
|
||||||
|
uint32_t strides[] = { sizeof(Vertex) };
|
||||||
|
cmdList->SetVertexBuffers(0, 1, vertexBuffers, offsets, strides);
|
||||||
|
cmdList->SetIndexBuffer(mIndexBufferView, 0);
|
||||||
|
cmdList->DrawIndexed(static_cast<uint32_t>(sizeof(kQuadIndices) / sizeof(kQuadIndices[0])));
|
||||||
|
|
||||||
|
EndRender();
|
||||||
|
|
||||||
|
cmdList->Close();
|
||||||
|
void* cmdLists[] = { cmdList };
|
||||||
|
cmdQueue->ExecuteCommandLists(1, cmdLists);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_P(QuadTest, RenderQuad) {
|
||||||
|
RHICommandQueue* cmdQueue = GetCommandQueue();
|
||||||
|
RHISwapChain* swapChain = GetSwapChain();
|
||||||
|
const int targetFrameCount = 30;
|
||||||
|
const char* screenshotFilename = GetScreenshotFilename(GetBackendType());
|
||||||
|
const int comparisonThreshold = GetComparisonThreshold(GetBackendType());
|
||||||
|
|
||||||
|
for (int frameCount = 0; frameCount <= targetFrameCount; ++frameCount) {
|
||||||
|
if (frameCount > 0) {
|
||||||
|
cmdQueue->WaitForPreviousFrame();
|
||||||
|
}
|
||||||
|
|
||||||
|
Log("[TEST] Quad MainLoop: frame %d", frameCount);
|
||||||
|
BeginRender();
|
||||||
|
RenderFrame();
|
||||||
|
|
||||||
|
if (frameCount >= targetFrameCount) {
|
||||||
|
cmdQueue->WaitForIdle();
|
||||||
|
Log("[TEST] Quad MainLoop: frame %d reached, capturing %s", frameCount, screenshotFilename);
|
||||||
|
ASSERT_TRUE(TakeScreenshot(screenshotFilename));
|
||||||
|
ASSERT_TRUE(CompareWithGoldenTemplate(screenshotFilename, "GT.ppm", static_cast<float>(comparisonThreshold)));
|
||||||
|
Log("[TEST] Quad MainLoop: frame %d compare passed", frameCount);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
swapChain->Present(0, 0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace
|
||||||
|
|
||||||
|
INSTANTIATE_TEST_SUITE_P(D3D12, QuadTest, ::testing::Values(RHIType::D3D12));
|
||||||
|
INSTANTIATE_TEST_SUITE_P(OpenGL, QuadTest, ::testing::Values(RHIType::OpenGL));
|
||||||
|
|
||||||
|
GTEST_API_ int main(int argc, char** argv) {
|
||||||
|
Logger::Get().Initialize();
|
||||||
|
Logger::Get().AddSink(std::make_unique<ConsoleLogSink>());
|
||||||
|
Logger::Get().SetMinimumLevel(LogLevel::Debug);
|
||||||
|
|
||||||
|
testing::InitGoogleTest(&argc, argv);
|
||||||
|
return RUN_ALL_TESTS();
|
||||||
|
}
|
||||||
@@ -122,6 +122,38 @@ TEST_P(RHITestFixture, Device_CreateUnorderedAccessView) {
|
|||||||
delete texture;
|
delete texture;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
TEST_P(RHITestFixture, Device_CreateShaderResourceView_FromInitialDataTexture) {
|
||||||
|
TextureDesc texDesc = {};
|
||||||
|
texDesc.width = 1;
|
||||||
|
texDesc.height = 1;
|
||||||
|
texDesc.depth = 1;
|
||||||
|
texDesc.mipLevels = 1;
|
||||||
|
texDesc.arraySize = 1;
|
||||||
|
texDesc.format = static_cast<uint32_t>(Format::R8G8B8A8_UNorm);
|
||||||
|
texDesc.textureType = static_cast<uint32_t>(TextureType::Texture2D);
|
||||||
|
texDesc.sampleCount = 1;
|
||||||
|
texDesc.sampleQuality = 0;
|
||||||
|
texDesc.flags = 0;
|
||||||
|
|
||||||
|
const uint8_t pixel[4] = { 255, 255, 255, 255 };
|
||||||
|
RHITexture* texture = GetDevice()->CreateTexture(texDesc, pixel, sizeof(pixel), 4);
|
||||||
|
ASSERT_NE(texture, nullptr);
|
||||||
|
|
||||||
|
ResourceViewDesc viewDesc = {};
|
||||||
|
viewDesc.format = static_cast<uint32_t>(Format::R8G8B8A8_UNorm);
|
||||||
|
viewDesc.dimension = ResourceViewDimension::Texture2D;
|
||||||
|
|
||||||
|
RHIResourceView* srv = GetDevice()->CreateShaderResourceView(texture, viewDesc);
|
||||||
|
ASSERT_NE(srv, nullptr);
|
||||||
|
EXPECT_TRUE(srv->IsValid());
|
||||||
|
EXPECT_EQ(srv->GetViewType(), ResourceViewType::ShaderResource);
|
||||||
|
|
||||||
|
srv->Shutdown();
|
||||||
|
delete srv;
|
||||||
|
texture->Shutdown();
|
||||||
|
delete texture;
|
||||||
|
}
|
||||||
|
|
||||||
TEST_P(RHITestFixture, Device_CreateVertexBufferView) {
|
TEST_P(RHITestFixture, Device_CreateVertexBufferView) {
|
||||||
BufferDesc bufferDesc = {};
|
BufferDesc bufferDesc = {};
|
||||||
bufferDesc.size = 256;
|
bufferDesc.size = 256;
|
||||||
|
|||||||
@@ -65,6 +65,7 @@ cmake --build build --config Debug
|
|||||||
cmake --build build --config Debug --target rhi_unit_tests
|
cmake --build build --config Debug --target rhi_unit_tests
|
||||||
cmake --build build --config Debug --target rhi_integration_minimal
|
cmake --build build --config Debug --target rhi_integration_minimal
|
||||||
cmake --build build --config Debug --target rhi_integration_triangle
|
cmake --build build --config Debug --target rhi_integration_triangle
|
||||||
|
cmake --build build --config Debug --target rhi_integration_quad
|
||||||
```
|
```
|
||||||
|
|
||||||
### 3.3 运行
|
### 3.3 运行
|
||||||
@@ -114,6 +115,7 @@ RHI 当前分成四类测试:
|
|||||||
| 抽象层单元测试 | `rhi_unit_tests` |
|
| 抽象层单元测试 | `rhi_unit_tests` |
|
||||||
| 抽象层集成测试 | `rhi_integration_minimal` |
|
| 抽象层集成测试 | `rhi_integration_minimal` |
|
||||||
| 抽象层集成测试 | `rhi_integration_triangle` |
|
| 抽象层集成测试 | `rhi_integration_triangle` |
|
||||||
|
| 抽象层集成测试 | `rhi_integration_quad` |
|
||||||
| D3D12 后端单元测试 | `rhi_d3d12_tests` |
|
| D3D12 后端单元测试 | `rhi_d3d12_tests` |
|
||||||
| OpenGL 后端单元测试 | `rhi_opengl_tests` |
|
| OpenGL 后端单元测试 | `rhi_opengl_tests` |
|
||||||
| D3D12 后端集成测试 | `d3d12_minimal_test` `d3d12_triangle_test` `d3d12_quad_test` `d3d12_sphere_test` |
|
| D3D12 后端集成测试 | `d3d12_minimal_test` `d3d12_triangle_test` `d3d12_quad_test` `d3d12_sphere_test` |
|
||||||
@@ -121,8 +123,7 @@ RHI 当前分成四类测试:
|
|||||||
|
|
||||||
说明:
|
说明:
|
||||||
|
|
||||||
- 抽象层集成测试目前只正式包含 `minimal` 与 `triangle`。
|
- 抽象层集成测试目前正式包含 `minimal`、`triangle` 与 `quad`。
|
||||||
- `quad` 仍在向纯 RHI 抽象测试迁移中,未进入本列表。
|
|
||||||
|
|
||||||
## 6. RHI 抽象层集成测试规范
|
## 6. RHI 抽象层集成测试规范
|
||||||
|
|
||||||
@@ -141,6 +142,10 @@ tests/RHI/integration/
|
|||||||
│ ├─ CMakeLists.txt
|
│ ├─ CMakeLists.txt
|
||||||
│ ├─ GT.ppm
|
│ ├─ GT.ppm
|
||||||
│ └─ main.cpp
|
│ └─ main.cpp
|
||||||
|
├─ quad/
|
||||||
|
│ ├─ CMakeLists.txt
|
||||||
|
│ ├─ GT.ppm
|
||||||
|
│ └─ main.cpp
|
||||||
├─ compare_ppm.py
|
├─ compare_ppm.py
|
||||||
└─ CMakeLists.txt
|
└─ CMakeLists.txt
|
||||||
```
|
```
|
||||||
@@ -157,6 +162,8 @@ tests/RHI/integration/
|
|||||||
- `minimal_opengl.ppm`
|
- `minimal_opengl.ppm`
|
||||||
- `triangle_d3d12.ppm`
|
- `triangle_d3d12.ppm`
|
||||||
- `triangle_opengl.ppm`
|
- `triangle_opengl.ppm`
|
||||||
|
- `quad_d3d12.ppm`
|
||||||
|
- `quad_opengl.ppm`
|
||||||
5. 两个后端都必须与同一张 `GT.ppm` 做比对。
|
5. 两个后端都必须与同一张 `GT.ppm` 做比对。
|
||||||
6. 新测试如果暴露抽象层缺口,应先补 RHI,再补测试。
|
6. 新测试如果暴露抽象层缺口,应先补 RHI,再补测试。
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user