summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--build/visual-studio/gfx-unit-test-tool/gfx-unit-test-tool.vcxproj2
-rw-r--r--build/visual-studio/gfx-unit-test-tool/gfx-unit-test-tool.vcxproj.filters6
-rw-r--r--slang-gfx.h2
-rw-r--r--tools/gfx-unit-test/copy-texture-tests.cpp42
-rw-r--r--tools/gfx-unit-test/gfx-test-texture-util.cpp10
-rw-r--r--tools/gfx-unit-test/gfx-test-texture-util.h6
-rw-r--r--tools/gfx-unit-test/gfx-test-util.cpp2
-rw-r--r--tools/gfx-unit-test/texture-types-tests.cpp707
-rw-r--r--tools/gfx-unit-test/trivial-copy-textures.slang303
-rw-r--r--tools/gfx/d3d12/render-d3d12.cpp6
-rw-r--r--tools/gfx/vulkan/render-vk.cpp2
11 files changed, 1041 insertions, 47 deletions
diff --git a/build/visual-studio/gfx-unit-test-tool/gfx-unit-test-tool.vcxproj b/build/visual-studio/gfx-unit-test-tool/gfx-unit-test-tool.vcxproj
index 43bac5358..ea9cc9bd4 100644
--- a/build/visual-studio/gfx-unit-test-tool/gfx-unit-test-tool.vcxproj
+++ b/build/visual-studio/gfx-unit-test-tool/gfx-unit-test-tool.vcxproj
@@ -296,6 +296,7 @@
<ClCompile Include="..\..\..\tools\gfx-unit-test\sampler-array.cpp" />
<ClCompile Include="..\..\..\tools\gfx-unit-test\shared-buffers-tests.cpp" />
<ClCompile Include="..\..\..\tools\gfx-unit-test\shared-textures-tests.cpp" />
+ <ClCompile Include="..\..\..\tools\gfx-unit-test\texture-types-tests.cpp" />
<ClCompile Include="..\..\..\tools\unit-test\slang-unit-test.cpp" />
</ItemGroup>
<ItemGroup>
@@ -309,6 +310,7 @@
<None Include="..\..\..\tools\gfx-unit-test\resolve-resource-shader.slang" />
<None Include="..\..\..\tools\gfx-unit-test\root-shader-parameter.slang" />
<None Include="..\..\..\tools\gfx-unit-test\sampler-array.slang" />
+ <None Include="..\..\..\tools\gfx-unit-test\trivial-copy-textures.slang" />
<None Include="..\..\..\tools\gfx-unit-test\trivial-copy.slang" />
</ItemGroup>
<ItemGroup>
diff --git a/build/visual-studio/gfx-unit-test-tool/gfx-unit-test-tool.vcxproj.filters b/build/visual-studio/gfx-unit-test-tool/gfx-unit-test-tool.vcxproj.filters
index 1fda831f1..6eae5a524 100644
--- a/build/visual-studio/gfx-unit-test-tool/gfx-unit-test-tool.vcxproj.filters
+++ b/build/visual-studio/gfx-unit-test-tool/gfx-unit-test-tool.vcxproj.filters
@@ -92,6 +92,9 @@
<ClCompile Include="..\..\..\tools\gfx-unit-test\gfx-test-texture-util.cpp">
<Filter>Source Files</Filter>
</ClCompile>
+ <ClCompile Include="..\..\..\tools\gfx-unit-test\texture-types-tests.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
</ItemGroup>
<ItemGroup>
<None Include="..\..\..\tools\gfx-unit-test\buffer-barrier-test.slang">
@@ -127,5 +130,8 @@
<None Include="..\..\..\tools\gfx-unit-test\trivial-copy.slang">
<Filter>Source Files</Filter>
</None>
+ <None Include="..\..\..\tools\gfx-unit-test\trivial-copy-textures.slang">
+ <Filter>Source Files</Filter>
+ </None>
</ItemGroup>
</Project> \ No newline at end of file
diff --git a/slang-gfx.h b/slang-gfx.h
index 3695a0352..5b7a2c807 100644
--- a/slang-gfx.h
+++ b/slang-gfx.h
@@ -785,6 +785,8 @@ public:
ShaderResource,
UnorderedAccess,
AccelerationStructure,
+
+ CountOf_,
};
struct RenderTargetDesc
diff --git a/tools/gfx-unit-test/copy-texture-tests.cpp b/tools/gfx-unit-test/copy-texture-tests.cpp
index 2999dc704..f332198b4 100644
--- a/tools/gfx-unit-test/copy-texture-tests.cpp
+++ b/tools/gfx-unit-test/copy-texture-tests.cpp
@@ -62,19 +62,13 @@ namespace gfx_test
this->context = context;
this->validationFormat = validationFormat;
- FormatInfo formatInfo;
- GFX_CHECK_CALL_ABORT(gfxGetFormatInfo(format, &formatInfo));
- auto texelSize = formatInfo.blockSizeInBytes / formatInfo.pixelsPerBlock;
-
this->srcTextureInfo = new TextureInfo();
this->srcTextureInfo->format = format;
this->srcTextureInfo->textureType = type;
- this->srcTextureInfo->texelSize = texelSize;
this->dstTextureInfo = new TextureInfo();
this->dstTextureInfo->format = format;
this->dstTextureInfo->textureType = type;
- this->dstTextureInfo->texelSize = texelSize;
}
void createRequiredResources()
@@ -123,9 +117,10 @@ namespace gfx_test
dstTexture.writeRef()));
auto bufferCopyExtents = bufferCopyInfo.extent;
+ auto texelSize = getTexelSize(dstTextureInfo->format);
size_t alignment;
device->getTextureRowAlignment(&alignment);
- alignedRowStride = (bufferCopyExtents.width * dstTextureInfo->texelSize + alignment - 1) & ~(alignment - 1);
+ alignedRowStride = (bufferCopyExtents.width * texelSize + alignment - 1) & ~(alignment - 1);
IBufferResource::Desc bufferDesc = {};
bufferDesc.sizeInBytes = bufferCopyExtents.height * bufferCopyExtents.depth * alignedRowStride;
bufferDesc.format = Format::Unknown;
@@ -255,14 +250,14 @@ namespace gfx_test
ValidationTextureData actual;
actual.extents = bufferCopyInfo.extent;
actual.textureData = results;
- actual.strides.x = dstTextureInfo->texelSize;
+ actual.strides.x = getTexelSize(dstTextureInfo->format);
actual.strides.y = (uint32_t)alignedRowStride;
actual.strides.z = actual.extents.height * actual.strides.y;
ValidationTextureData expectedCopied;
expectedCopied.extents = srcMipExtent;
expectedCopied.textureData = expectedCopiedData;
- expectedCopied.strides.x = srcTextureInfo->texelSize;
+ expectedCopied.strides.x = getTexelSize(srcTextureInfo->format);
expectedCopied.strides.y = expectedCopied.extents.width * expectedCopied.strides.x;
expectedCopied.strides.z = expectedCopied.extents.height * expectedCopied.strides.y;
@@ -271,7 +266,7 @@ namespace gfx_test
{
expectedOriginal.extents = bufferCopyInfo.extent;
expectedOriginal.textureData = expectedOriginalData;
- expectedOriginal.strides.x = dstTextureInfo->texelSize;
+ expectedOriginal.strides.x = getTexelSize(dstTextureInfo->format);
expectedOriginal.strides.y = expectedOriginal.extents.width * expectedOriginal.strides.x;
expectedOriginal.strides.z = expectedOriginal.extents.height * expectedOriginal.strides.y;
}
@@ -768,33 +763,6 @@ namespace gfx_test
}
}
- SLANG_UNIT_TEST(copyTextureTests)
- {
- runTestImpl(copyTextureTestImpl<SimpleCopyTexture>, unitTestContext, Slang::RenderApiFlag::D3D12);
- runTestImpl(copyTextureTestImpl<SimpleCopyTexture>, unitTestContext, Slang::RenderApiFlag::Vulkan);
-
- runTestImpl(copyTextureTestImpl<CopyTextureSection>, unitTestContext, Slang::RenderApiFlag::D3D12);
- runTestImpl(copyTextureTestImpl<CopyTextureSection>, unitTestContext, Slang::RenderApiFlag::Vulkan);
-
- runTestImpl(copyTextureTestImpl<LargeSrcToSmallDst>, unitTestContext, Slang::RenderApiFlag::D3D12);
- runTestImpl(copyTextureTestImpl<LargeSrcToSmallDst>, unitTestContext, Slang::RenderApiFlag::Vulkan);
-
- runTestImpl(copyTextureTestImpl<SmallSrcToLargeDst>, unitTestContext, Slang::RenderApiFlag::D3D12);
- runTestImpl(copyTextureTestImpl<SmallSrcToLargeDst>, unitTestContext, Slang::RenderApiFlag::Vulkan);
-
- runTestImpl(copyTextureTestImpl<CopyBetweenMips>, unitTestContext, Slang::RenderApiFlag::D3D12);
- runTestImpl(copyTextureTestImpl<CopyBetweenMips>, unitTestContext, Slang::RenderApiFlag::Vulkan);
-
- runTestImpl(copyTextureTestImpl<CopyBetweenLayers>, unitTestContext, Slang::RenderApiFlag::D3D12);
- runTestImpl(copyTextureTestImpl<CopyBetweenLayers>, unitTestContext, Slang::RenderApiFlag::Vulkan);
-
- runTestImpl(copyTextureTestImpl<CopyWithOffsets>, unitTestContext, Slang::RenderApiFlag::D3D12);
- runTestImpl(copyTextureTestImpl<CopyWithOffsets>, unitTestContext, Slang::RenderApiFlag::Vulkan);
-
- runTestImpl(copyTextureTestImpl<CopySectionWithSetExtent>, unitTestContext, Slang::RenderApiFlag::D3D12);
- runTestImpl(copyTextureTestImpl<CopySectionWithSetExtent>, unitTestContext, Slang::RenderApiFlag::Vulkan);
- }
-
SLANG_UNIT_TEST(copyTextureSimple)
{
runTestImpl(copyTextureTestImpl<SimpleCopyTexture>, unitTestContext, Slang::RenderApiFlag::D3D12);
diff --git a/tools/gfx-unit-test/gfx-test-texture-util.cpp b/tools/gfx-unit-test/gfx-test-texture-util.cpp
index 24cd1c4a9..c7c85db58 100644
--- a/tools/gfx-unit-test/gfx-test-texture-util.cpp
+++ b/tools/gfx-unit-test/gfx-test-texture-util.cpp
@@ -1,4 +1,5 @@
#include "gfx-test-texture-util.h"
+#include "gfx-test-util.h"
#include "tools/unit-test/slang-unit-test.h"
#include <slang-com-ptr.h>
@@ -28,6 +29,13 @@ namespace gfx_test
}
}
+ uint32_t getTexelSize(Format format)
+ {
+ FormatInfo info;
+ GFX_CHECK_CALL_ABORT(gfxGetFormatInfo(format, &info));
+ return info.blockSizeInBytes / info.pixelsPerBlock;
+ }
+
uint32_t getSubresourceIndex(uint32_t mipLevel, uint32_t mipLevelCount, uint32_t baseArrayLayer)
{
return baseArrayLayer * mipLevelCount + mipLevel;
@@ -145,7 +153,7 @@ namespace gfx_test
auto extents = texture->extents;
auto arrayLayers = texture->arrayLayerCount;
auto mipLevels = texture->mipLevelCount;
- auto texelSize = texture->texelSize;
+ auto texelSize = getTexelSize(texture->format);
for (uint32_t layer = 0; layer < arrayLayers; ++layer)
{
diff --git a/tools/gfx-unit-test/gfx-test-texture-util.h b/tools/gfx-unit-test/gfx-test-texture-util.h
index 57a72d54a..7e59c60e1 100644
--- a/tools/gfx-unit-test/gfx-test-texture-util.h
+++ b/tools/gfx-unit-test/gfx-test-texture-util.h
@@ -157,7 +157,6 @@ namespace gfx_test
struct TextureInfo : RefObject
{
Format format;
- uint32_t texelSize;
ITextureResource::Type textureType;
ITextureResource::Size extents;
@@ -168,8 +167,9 @@ namespace gfx_test
List<ITextureResource::SubresourceData> subresourceDatas;
};
- RefPtr<ValidationTextureFormatBase> getValidationTextureFormat(Format format);
- TextureAspect getTextureAspect(gfx::Format format);
+ TextureAspect getTextureAspect(Format format);
+ uint32_t getTexelSize(Format format);
uint32_t getSubresourceIndex(uint32_t mipLevel, uint32_t mipLevelCount, uint32_t baseArrayLayer);
+ RefPtr<ValidationTextureFormatBase> getValidationTextureFormat(Format format);
void generateTextureData(RefPtr<TextureInfo> texture, ValidationTextureFormatBase* validationFormat);
}
diff --git a/tools/gfx-unit-test/gfx-test-util.cpp b/tools/gfx-unit-test/gfx-test-util.cpp
index ecd19f179..e9f683524 100644
--- a/tools/gfx-unit-test/gfx-test-util.cpp
+++ b/tools/gfx-unit-test/gfx-test-util.cpp
@@ -127,7 +127,6 @@ namespace gfx_test
size_t pixelSize = 0;
GFX_CHECK_CALL_ABORT(device->readTextureResource(
texture, state, resultBlob.writeRef(), &rowPitch, &pixelSize));
- auto result = (float*)resultBlob->getBufferPointer();
// Compare results.
for (size_t row = 0; row < rowCount; row++)
{
@@ -146,7 +145,6 @@ namespace gfx_test
GFX_CHECK_CALL_ABORT(device->readBufferResource(
buffer, offset, expectedBufferSize, resultBlob.writeRef()));
SLANG_CHECK(resultBlob->getBufferSize() == expectedBufferSize);
- auto result = (float*)resultBlob->getBufferPointer();
// Compare results.
SLANG_CHECK(memcmp(resultBlob->getBufferPointer(), (uint8_t*)expectedResult, expectedBufferSize) == 0);
}
diff --git a/tools/gfx-unit-test/texture-types-tests.cpp b/tools/gfx-unit-test/texture-types-tests.cpp
new file mode 100644
index 000000000..5fdeb2622
--- /dev/null
+++ b/tools/gfx-unit-test/texture-types-tests.cpp
@@ -0,0 +1,707 @@
+#include "tools/unit-test/slang-unit-test.h"
+
+#include "slang-gfx.h"
+#include "gfx-test-util.h"
+#include "gfx-test-texture-util.h"
+#include "tools/gfx-util/shader-cursor.h"
+#include "source/core/slang-basic.h"
+
+#if SLANG_WINDOWS_FAMILY
+#include <d3d12.h>
+#endif
+
+#include <stdlib.h>
+#include <stdio.h>
+
+#define STB_IMAGE_WRITE_IMPLEMENTATION
+#include "external/stb/stb_image_write.h"
+
+using namespace Slang;
+using namespace gfx;
+
+namespace gfx_test
+{
+ Slang::Result writeImage(
+ const char* filename,
+ ISlangBlob* pixels,
+ uint32_t width,
+ uint32_t height,
+ size_t rowPitch = 0)
+ {
+ int stbResult = 0;
+ if (rowPitch == 0)
+ {
+ stbResult = stbi_write_hdr(filename, width, height, 4, (float*)pixels->getBufferPointer());
+ }
+ else
+ {
+ List<float> data;
+ for (Int y = 0; y < height; ++y)
+ {
+ for (Int x = 0; x < width; ++x)
+ {
+ for (Int c = 0; c < 4; ++c)
+ {
+ auto rowPtr = (char*)pixels->getBufferPointer() + y * rowPitch;
+ auto channelPtr = (float*)rowPtr + x * 4 + c;
+ data.add(*channelPtr);
+ }
+ }
+ }
+ stbResult = stbi_write_hdr(filename, width, height, 4, data.getBuffer());
+ }
+
+ return stbResult ? SLANG_OK : SLANG_FAIL;
+ }
+
+ struct BaseTextureViewTest
+ {
+ IDevice* device;
+ UnitTestContext* context;
+
+ IResourceView::Type viewType;
+ size_t alignedRowStride;
+
+ RefPtr<TextureInfo> textureInfo;
+ RefPtr<ValidationTextureFormatBase> validationFormat;
+
+ ComPtr<ITextureResource> texture;
+ ComPtr<IResourceView> textureView;
+ ComPtr<IBufferResource> resultsBuffer;
+ ComPtr<IResourceView> bufferView;
+
+ ComPtr<ISamplerState> sampler;
+
+ const void* expectedTextureData;
+
+ void init(
+ IDevice* device,
+ UnitTestContext* context,
+ Format format,
+ RefPtr<ValidationTextureFormatBase> validationFormat,
+ IResourceView::Type viewType,
+ IResource::Type type)
+ {
+ this->device = device;
+ this->context = context;
+ this->validationFormat = validationFormat;
+ this->viewType = viewType;
+
+ this->textureInfo = new TextureInfo();
+ this->textureInfo->format = format;
+ this->textureInfo->textureType = type;
+ }
+
+ ResourceState getDefaultResourceStateForViewType(IResourceView::Type type)
+ {
+ switch (type)
+ {
+ case IResourceView::Type::RenderTarget:
+ return ResourceState::RenderTarget;
+ case IResourceView::Type::DepthStencil:
+ return ResourceState::DepthWrite;
+ case IResourceView::Type::ShaderResource:
+ return ResourceState::ShaderResource;
+ case IResourceView::Type::UnorderedAccess:
+ return ResourceState::UnorderedAccess;
+ case IResourceView::Type::AccelerationStructure:
+ return ResourceState::AccelerationStructure;
+ default:
+ return ResourceState::Undefined;
+ }
+ }
+
+ String getShaderEntryPoint()
+ {
+ String base = "resourceViewTest";
+ String shape;
+ String view;
+
+ switch (textureInfo->textureType)
+ {
+ case IResource::Type::Texture1D:
+ shape = "1D";
+ break;
+ case IResource::Type::Texture2D:
+ shape = "2D";
+ break;
+ case IResource::Type::Texture3D:
+ shape = "3D";
+ break;
+ case IResource::Type::TextureCube:
+ shape = "Cube";
+ break;
+ default:
+ assert(!"Invalid texture shape");
+ SLANG_CHECK_ABORT(false);
+ }
+
+ switch (viewType)
+ {
+ case IResourceView::Type::RenderTarget:
+ view = "Render";
+ break;
+ case IResourceView::Type::DepthStencil:
+ view = "Depth";
+ break;
+ case IResourceView::Type::ShaderResource:
+ view = "Shader";
+ break;
+ case IResourceView::Type::UnorderedAccess:
+ view = "Unordered";
+ break;
+ case IResourceView::Type::AccelerationStructure:
+ view = "Accel";
+ break;
+ default:
+ assert(!"Invalid resource view");
+ SLANG_CHECK_ABORT(false);
+ }
+
+ return base + shape + view;
+ }
+
+
+ };
+
+ // used for shaderresource and unorderedaccess
+ struct ShaderAndUnorderedTests : BaseTextureViewTest
+ {
+ void createRequiredResources()
+ {
+ ITextureResource::Desc textureDesc = {};
+ textureDesc.type = textureInfo->textureType;
+ textureDesc.numMipLevels = textureInfo->mipLevelCount;
+ textureDesc.arraySize = textureInfo->arrayLayerCount;
+ textureDesc.size = textureInfo->extents;
+ textureDesc.defaultState = getDefaultResourceStateForViewType(viewType);
+ textureDesc.allowedStates = ResourceStateSet(
+ textureDesc.defaultState,
+ ResourceState::CopySource,
+ ResourceState::CopyDestination);
+ textureDesc.format = textureInfo->format;
+
+ GFX_CHECK_CALL_ABORT(device->createTextureResource(
+ textureDesc,
+ textureInfo->subresourceDatas.getBuffer(),
+ texture.writeRef()));
+
+ IResourceView::Desc textureViewDesc = {};
+ textureViewDesc.type = viewType;
+ textureViewDesc.format = textureDesc.format; // TODO: Handle typeless formats - gfxIsTypelessFormat(format) ? convertTypelessFormat(format) : format;
+ GFX_CHECK_CALL_ABORT(device->createTextureView(texture, textureViewDesc, textureView.writeRef()));
+
+ auto texelSize = getTexelSize(textureInfo->format);
+ size_t alignment;
+ device->getTextureRowAlignment(&alignment);
+ alignedRowStride = (textureInfo->extents.width * texelSize + alignment - 1) & ~(alignment - 1);
+ IBufferResource::Desc bufferDesc = {};
+ // All of the values read back from the shader will be uint32_t
+ bufferDesc.sizeInBytes = textureDesc.size.width * textureDesc.size.height * textureDesc.size.depth * texelSize * sizeof(uint32_t);
+ bufferDesc.format = Format::Unknown;
+ bufferDesc.elementSize = sizeof(uint32_t);
+ bufferDesc.defaultState = ResourceState::UnorderedAccess;
+ bufferDesc.allowedStates = ResourceStateSet(
+ bufferDesc.defaultState,
+ ResourceState::CopyDestination,
+ ResourceState::CopySource);
+ bufferDesc.memoryType = MemoryType::DeviceLocal;
+
+ GFX_CHECK_CALL_ABORT(device->createBufferResource(bufferDesc, nullptr, resultsBuffer.writeRef()));
+
+ IResourceView::Desc bufferViewDesc = {};
+ bufferViewDesc.type = IResourceView::Type::UnorderedAccess;
+ bufferViewDesc.format = Format::Unknown;
+ GFX_CHECK_CALL_ABORT(device->createBufferView(resultsBuffer, nullptr, bufferViewDesc, bufferView.writeRef()));
+ }
+
+ void submitShaderWork(const char* entryPoint)
+ {
+ Slang::ComPtr<ITransientResourceHeap> transientHeap;
+ ITransientResourceHeap::Desc transientHeapDesc = {};
+ transientHeapDesc.constantBufferSize = 4096;
+ GFX_CHECK_CALL_ABORT(
+ device->createTransientResourceHeap(transientHeapDesc, transientHeap.writeRef()));
+
+ ComPtr<IShaderProgram> shaderProgram;
+ slang::ProgramLayout* slangReflection;
+ GFX_CHECK_CALL_ABORT(loadComputeProgram(device, shaderProgram, "trivial-copy-textures", entryPoint, slangReflection));
+
+ ComputePipelineStateDesc pipelineDesc = {};
+ pipelineDesc.program = shaderProgram.get();
+ ComPtr<gfx::IPipelineState> pipelineState;
+ GFX_CHECK_CALL_ABORT(
+ device->createComputePipelineState(pipelineDesc, pipelineState.writeRef()));
+
+ // We have done all the set up work, now it is time to start recording a command buffer for
+ // GPU execution.
+ {
+ ICommandQueue::Desc queueDesc = { ICommandQueue::QueueType::Graphics };
+ auto queue = device->createCommandQueue(queueDesc);
+
+ auto commandBuffer = transientHeap->createCommandBuffer();
+ auto encoder = commandBuffer->encodeComputeCommands();
+
+ auto rootObject = encoder->bindPipeline(pipelineState);
+
+ ShaderCursor entryPointCursor(
+ rootObject->getEntryPoint(0)); // get a cursor the the first entry-point.
+
+ auto width = textureInfo->extents.width;
+ auto height = textureInfo->extents.height;
+ auto depth = textureInfo->extents.depth;
+
+ entryPointCursor["width"].setData(width);
+ entryPointCursor["height"].setData(height);
+ entryPointCursor["depth"].setData(depth);
+
+ // Bind texture view to the entry point
+ entryPointCursor["resourceView"].setResource(textureView); // TODO: Bind nullptr and make sure it doesn't splut - should be 0 everywhere
+ entryPointCursor["testResults"].setResource(bufferView);
+
+ if (sampler) entryPointCursor["sampler"].setSampler(sampler); // TODO: Bind nullptr and make sure it doesn't splut
+
+ auto bufferElementCount = width * height * depth;
+ encoder->dispatchCompute(bufferElementCount, 1, 1);
+ encoder->endEncoding();
+ commandBuffer->close();
+ queue->executeCommandBuffer(commandBuffer);
+ queue->waitOnHost();
+ }
+ }
+
+ void validateTextureValues(ValidationTextureData actual, ValidationTextureData original)
+ {
+ // TODO: needs to be extended to cover mip levels and array layers
+ for (Int x = 0; x < actual.extents.width; ++x)
+ {
+ for (Int y = 0; y < actual.extents.height; ++y)
+ {
+ for (Int z = 0; z < actual.extents.depth; ++z)
+ {
+ auto actualBlock = (uint8_t*)actual.getBlockAt(x, y, z);
+ for (Int i = 0; i < 4; ++i)
+ {
+ SLANG_CHECK(actualBlock[i] == 1);
+ }
+ }
+ }
+ }
+ }
+
+ void checkTestResults()
+ {
+ // Shader resources are read-only, so we don't need to check that writes to the resource were correct.
+ if (viewType != IResourceView::Type::ShaderResource)
+ {
+ ComPtr<ISlangBlob> textureBlob;
+ size_t rowPitch;
+ size_t pixelSize;
+ GFX_CHECK_CALL_ABORT(device->readTextureResource(texture, ResourceState::CopySource, textureBlob.writeRef(), &rowPitch, &pixelSize));
+ auto textureValues = (uint8_t*)textureBlob->getBufferPointer();
+
+ ValidationTextureData textureResults;
+ textureResults.extents = textureInfo->extents;
+ textureResults.textureData = textureValues;
+ textureResults.strides.x = pixelSize;
+ textureResults.strides.y = rowPitch;
+ textureResults.strides.z = textureResults.extents.height * textureResults.strides.y;
+
+ ValidationTextureData originalData;
+ originalData.extents = textureInfo->extents;
+ originalData.textureData = textureInfo->subresourceDatas.getBuffer();
+ originalData.strides.x = pixelSize;
+ originalData.strides.y = textureInfo->extents.width * originalData.strides.x;
+ originalData.strides.z = textureInfo->extents.height * originalData.strides.y;
+
+ validateTextureValues(textureResults, originalData);
+ }
+
+ ComPtr<ISlangBlob> bufferBlob;
+ GFX_CHECK_CALL_ABORT(device->readBufferResource(resultsBuffer, 0, resultsBuffer->getDesc()->sizeInBytes, bufferBlob.writeRef()));
+ auto results = (uint32_t*)bufferBlob->getBufferPointer();
+
+ auto elementCount = textureInfo->extents.width * textureInfo->extents.height * textureInfo->extents.depth * 4;
+ auto castedTextureData = (uint8_t*)expectedTextureData;
+ for (Int i = 0; i < elementCount; ++i)
+ {
+ SLANG_CHECK(results[i] == castedTextureData[i]);
+ }
+ }
+
+ void run()
+ {
+ // TODO: Should test with samplers
+// ISamplerState::Desc samplerDesc;
+// sampler = device->createSamplerState(samplerDesc);
+
+ // TODO: Should test multiple mip levels and array layers
+ textureInfo->extents.width = 4;
+ textureInfo->extents.height = (textureInfo->textureType == IResource::Type::Texture1D) ? 1 : 4;
+ textureInfo->extents.depth = (textureInfo->textureType != IResource::Type::Texture3D) ? 1 : 2;
+ textureInfo->mipLevelCount = 1;
+ textureInfo->arrayLayerCount = 1;
+ generateTextureData(textureInfo, validationFormat);
+
+ // We need to save the pointer to the original texture data for results checking because the texture will be
+ // overwritten during testing (if the texture can be written to).
+ expectedTextureData = textureInfo->subresourceDatas[getSubresourceIndex(0, 1, 0)].data;
+
+ createRequiredResources();
+ auto entryPointName = getShaderEntryPoint();
+ //printf("%s\n", entryPointName.getBuffer());
+ submitShaderWork(entryPointName.getBuffer());
+
+ checkTestResults();
+ }
+ };
+
+ // used for rendertarget and depthstencil
+ struct RenderTargetTests : BaseTextureViewTest
+ {
+ struct Vertex
+ {
+ float position[3];
+ float color[3];
+ };
+
+ const int kVertexCount = 12;
+ const Vertex kVertexData[12] =
+ {
+ // Triangle 1
+ { { 0, 0, 0.5 }, { 1, 0, 0 } },
+ { { 1, 1, 0.5 }, { 1, 0, 0 } },
+ { { -1, 1, 0.5 }, { 1, 0, 0 } },
+
+ // Triangle 2
+ { { -1, 1, 0.5 }, { 0, 1, 0 } },
+ { { 0, 0, 0.5 }, { 0, 1, 0 } },
+ { { -1, -1, 0.5 }, { 0, 1, 0 } },
+
+ // Triangle 3
+ { { -1, -1, 0.5 }, { 0, 0, 1 } },
+ { { 0, 0, 0.5 }, { 0, 0, 1 } },
+ { { 1, -1, 0.5 }, { 0, 0, 1 } },
+
+ // Triangle 4
+ { { 1, -1, 0.5 }, { 0, 0, 0 } },
+ { { 0, 0, 0.5 }, { 0, 0, 0 } },
+ { { 1, 1, 0.5 }, { 0, 0, 0 } },
+ };
+
+ int sampleCount = 1;
+
+ ComPtr<ITransientResourceHeap> transientHeap;
+ ComPtr<IPipelineState> pipelineState;
+ ComPtr<IRenderPassLayout> renderPass;
+ ComPtr<IFramebuffer> framebuffer;
+
+ ComPtr<ITextureResource> sampledTexture;
+ ComPtr<IBufferResource> vertexBuffer;
+
+ void createRequiredResources()
+ {
+ IBufferResource::Desc vertexBufferDesc;
+ vertexBufferDesc.type = IResource::Type::Buffer;
+ vertexBufferDesc.sizeInBytes = kVertexCount * sizeof(Vertex);
+ vertexBufferDesc.defaultState = ResourceState::VertexBuffer;
+ vertexBufferDesc.allowedStates = ResourceState::VertexBuffer;
+ vertexBuffer = device->createBufferResource(vertexBufferDesc, &kVertexData[0]);
+ SLANG_CHECK_ABORT(vertexBuffer != nullptr);
+
+ VertexStreamDesc vertexStreams[] = {
+ { sizeof(Vertex), InputSlotClass::PerVertex, 0 },
+ };
+
+ InputElementDesc inputElements[] = {
+ // Vertex buffer data
+ { "POSITION", 0, Format::R32G32B32_FLOAT, offsetof(Vertex, position), 0 },
+ { "COLOR", 0, Format::R32G32B32_FLOAT, offsetof(Vertex, color), 0 },
+ };
+
+ ITextureResource::Desc sampledTexDesc = {};
+ sampledTexDesc.type = textureInfo->textureType;
+ sampledTexDesc.numMipLevels = textureInfo->mipLevelCount;
+ sampledTexDesc.arraySize = textureInfo->arrayLayerCount;
+ sampledTexDesc.size = textureInfo->extents;
+ sampledTexDesc.defaultState = getDefaultResourceStateForViewType(viewType);
+ sampledTexDesc.allowedStates = ResourceStateSet(
+ sampledTexDesc.defaultState,
+ ResourceState::ResolveSource,
+ ResourceState::CopySource);
+ sampledTexDesc.format = textureInfo->format;
+ sampledTexDesc.sampleDesc.numSamples = sampleCount;
+
+ GFX_CHECK_CALL_ABORT(device->createTextureResource(
+ sampledTexDesc,
+ textureInfo->subresourceDatas.getBuffer(),
+ sampledTexture.writeRef()));
+
+ ITextureResource::Desc texDesc = {};
+ texDesc.type = textureInfo->textureType;
+ texDesc.numMipLevels = textureInfo->mipLevelCount;
+ texDesc.arraySize = textureInfo->arrayLayerCount;
+ texDesc.size = textureInfo->extents;
+ texDesc.defaultState = ResourceState::ResolveDestination;
+ texDesc.allowedStates = ResourceStateSet(
+ ResourceState::ResolveDestination,
+ ResourceState::CopySource);
+ texDesc.format = textureInfo->format;
+
+ GFX_CHECK_CALL_ABORT(device->createTextureResource(
+ texDesc,
+ textureInfo->subresourceDatas.getBuffer(),
+ texture.writeRef()));
+
+ IInputLayout::Desc inputLayoutDesc = {};
+ inputLayoutDesc.inputElementCount = SLANG_COUNT_OF(inputElements);
+ inputLayoutDesc.inputElements = inputElements;
+ inputLayoutDesc.vertexStreamCount = SLANG_COUNT_OF(vertexStreams);
+ inputLayoutDesc.vertexStreams = vertexStreams;
+ auto inputLayout = device->createInputLayout(inputLayoutDesc);
+ SLANG_CHECK_ABORT(inputLayout != nullptr);
+
+ ITransientResourceHeap::Desc transientHeapDesc = {};
+ transientHeapDesc.constantBufferSize = 4096;
+ GFX_CHECK_CALL_ABORT(
+ device->createTransientResourceHeap(transientHeapDesc, transientHeap.writeRef()));
+
+ ComPtr<IShaderProgram> shaderProgram;
+ slang::ProgramLayout* slangReflection;
+ GFX_CHECK_CALL_ABORT(loadGraphicsProgram(device, shaderProgram, "trivial-copy-textures", "vertexMain", "fragmentMain", slangReflection));
+
+ IFramebufferLayout::AttachmentLayout attachmentLayout;
+ attachmentLayout.format = textureInfo->format;
+ attachmentLayout.sampleCount = sampleCount;
+
+ IFramebufferLayout::Desc framebufferLayoutDesc;
+ framebufferLayoutDesc.renderTargetCount = 1;
+ framebufferLayoutDesc.renderTargets = &attachmentLayout;
+ ComPtr<gfx::IFramebufferLayout> framebufferLayout = device->createFramebufferLayout(framebufferLayoutDesc);
+ SLANG_CHECK_ABORT(framebufferLayout != nullptr);
+
+ GraphicsPipelineStateDesc pipelineDesc = {};
+ pipelineDesc.program = shaderProgram.get();
+ pipelineDesc.inputLayout = inputLayout;
+ pipelineDesc.framebufferLayout = framebufferLayout;
+ pipelineDesc.depthStencil.depthTestEnable = false;
+ pipelineDesc.depthStencil.depthWriteEnable = false;
+ GFX_CHECK_CALL_ABORT(
+ device->createGraphicsPipelineState(pipelineDesc, pipelineState.writeRef()));
+
+ IRenderPassLayout::Desc renderPassDesc = {};
+ renderPassDesc.framebufferLayout = framebufferLayout;
+ renderPassDesc.renderTargetCount = 1;
+ IRenderPassLayout::AttachmentAccessDesc renderTargetAccess = {};
+ renderTargetAccess.loadOp = IRenderPassLayout::AttachmentLoadOp::Clear;
+ renderTargetAccess.storeOp = IRenderPassLayout::AttachmentStoreOp::Store;
+ renderTargetAccess.initialState = getDefaultResourceStateForViewType(viewType);
+ renderTargetAccess.finalState = ResourceState::ResolveSource;
+ renderPassDesc.renderTargetAccess = &renderTargetAccess;
+ GFX_CHECK_CALL_ABORT(device->createRenderPassLayout(renderPassDesc, renderPass.writeRef()));
+
+ gfx::IResourceView::Desc colorBufferViewDesc;
+ memset(&colorBufferViewDesc, 0, sizeof(colorBufferViewDesc));
+ colorBufferViewDesc.format = textureInfo->format;
+ colorBufferViewDesc.renderTarget.shape = textureInfo->textureType; // TODO: TextureCube?
+ colorBufferViewDesc.type = viewType;
+ auto rtv = device->createTextureView(sampledTexture, colorBufferViewDesc);
+
+ gfx::IFramebuffer::Desc framebufferDesc;
+ framebufferDesc.renderTargetCount = 1;
+ framebufferDesc.depthStencilView = nullptr;
+ framebufferDesc.renderTargetViews = rtv.readRef();
+ framebufferDesc.layout = framebufferLayout;
+ GFX_CHECK_CALL_ABORT(device->createFramebuffer(framebufferDesc, framebuffer.writeRef()));
+
+ auto texelSize = getTexelSize(textureInfo->format);
+ size_t alignment;
+ device->getTextureRowAlignment(&alignment);
+ alignedRowStride = (textureInfo->extents.width * texelSize + alignment - 1) & ~(alignment - 1);
+ }
+
+ void submitShaderWork(const char* entryPointName)
+ {
+ ICommandQueue::Desc queueDesc = { ICommandQueue::QueueType::Graphics };
+ auto queue = device->createCommandQueue(queueDesc);
+
+ auto commandBuffer = transientHeap->createCommandBuffer();
+ auto renderEncoder = commandBuffer->encodeRenderCommands(renderPass, framebuffer);
+ auto rootObject = renderEncoder->bindPipeline(pipelineState);
+
+ gfx::Viewport viewport = {};
+ viewport.maxZ = textureInfo->extents.depth;
+ viewport.extentX = textureInfo->extents.width;
+ viewport.extentY = textureInfo->extents.height;
+ renderEncoder->setViewportAndScissor(viewport);
+
+ renderEncoder->setVertexBuffer(0, vertexBuffer);
+ renderEncoder->setPrimitiveTopology(PrimitiveTopology::TriangleList);
+ renderEncoder->draw(kVertexCount, 0);
+ renderEncoder->endEncoding();
+
+ auto resourceEncoder = commandBuffer->encodeResourceCommands();
+
+ if (sampleCount > 1)
+ {
+ SubresourceRange msaaSubresource = {};
+ msaaSubresource.aspectMask = TextureAspect::Color;
+ msaaSubresource.mipLevel = 0;
+ msaaSubresource.mipLevelCount = 1;
+ msaaSubresource.baseArrayLayer = 0;
+ msaaSubresource.layerCount = 1;
+
+ SubresourceRange dstSubresource = {};
+ dstSubresource.aspectMask = TextureAspect::Color;
+ dstSubresource.mipLevel = 0;
+ dstSubresource.mipLevelCount = 1;
+ dstSubresource.baseArrayLayer = 0;
+ dstSubresource.layerCount = 1;
+
+ resourceEncoder->resolveResource(sampledTexture, ResourceState::ResolveSource, msaaSubresource, texture, ResourceState::ResolveDestination, dstSubresource);
+ resourceEncoder->textureBarrier(texture, ResourceState::ResolveDestination, ResourceState::CopySource);
+ }
+ else
+ {
+ resourceEncoder->textureBarrier(sampledTexture, ResourceState::ResolveSource, ResourceState::CopySource);
+ }
+ resourceEncoder->endEncoding();
+ commandBuffer->close();
+ queue->executeCommandBuffer(commandBuffer);
+ queue->waitOnHost();
+ }
+
+ // TODO: Should take a value indicating the slice that was rendered into
+ // TODO: Needs to handle either the correct slice or array layer (will not always check z)
+ void validateTextureValues(ValidationTextureData actual)
+ {
+ for (Int x = 0; x < actual.extents.width; ++x)
+ {
+ for (Int y = 0; y < actual.extents.height; ++y)
+ {
+ for (Int z = 0; z < actual.extents.depth; ++z)
+ {
+ auto actualBlock = (float*)actual.getBlockAt(x, y, z);
+ for (Int i = 0; i < 4; ++i)
+ {
+ if (z == 0)
+ {
+ // Slice being rendered into
+ SLANG_CHECK(actualBlock[i] == (float)i + 1);
+ }
+ else
+ {
+ SLANG_CHECK(actualBlock[i] == 0.0f);
+ }
+ }
+ }
+ }
+ }
+ }
+
+ void checkTestResults()
+ {
+ ComPtr<ISlangBlob> textureBlob;
+ size_t rowPitch;
+ size_t pixelSize;
+ if (sampleCount > 1)
+ {
+ GFX_CHECK_CALL_ABORT(device->readTextureResource(texture, ResourceState::CopySource, textureBlob.writeRef(), &rowPitch, &pixelSize));
+ }
+ else
+ {
+ GFX_CHECK_CALL_ABORT(device->readTextureResource(sampledTexture, ResourceState::CopySource, textureBlob.writeRef(), &rowPitch, &pixelSize));
+ }
+ auto textureValues = (float*)textureBlob->getBufferPointer();
+
+ ValidationTextureData textureResults;
+ textureResults.extents = textureInfo->extents;
+ textureResults.textureData = textureValues;
+ textureResults.strides.x = pixelSize;
+ textureResults.strides.y = rowPitch;
+ textureResults.strides.z = textureResults.extents.height * textureResults.strides.y;
+
+ validateTextureValues(textureResults);
+ }
+
+ void run()
+ {
+ auto entryPointName = getShaderEntryPoint();
+// printf("%s\n", entryPointName.getBuffer());
+
+ // TODO: Sampler state and null state?
+// ISamplerState::Desc samplerDesc;
+// sampler = device->createSamplerState(samplerDesc);
+
+ textureInfo->extents.width = 4;
+ textureInfo->extents.height = (textureInfo->textureType == IResource::Type::Texture1D) ? 1 : 4;
+ textureInfo->extents.depth = (textureInfo->textureType != IResource::Type::Texture3D) ? 1 : 2;
+ textureInfo->mipLevelCount = 1;
+ textureInfo->arrayLayerCount = 1;
+ generateTextureData(textureInfo, validationFormat);
+
+ // We need to save the pointer to the original texture data for results checking because the texture will be
+ // overwritten during testing (if the texture can be written to).
+ expectedTextureData = textureInfo->subresourceDatas[getSubresourceIndex(0, 1, 0)].data;
+
+ createRequiredResources();
+ submitShaderWork(entryPointName.getBuffer());
+
+ checkTestResults();
+ }
+ };
+
+ void shaderAndUnorderedTestImpl(IDevice* device, UnitTestContext* context)
+ {
+ // TODO: Buffer and TextureCube
+ for (Int i = 2; i < (int32_t)IResource::Type::TextureCube; ++i)
+ {
+ for (Int j = 3; j < (int32_t)IResourceView::Type::AccelerationStructure; ++j)
+ {
+ auto shape = (IResource::Type)i;
+ auto view = (IResourceView::Type)j;
+ auto format = Format::R8G8B8A8_UINT;
+ auto validationFormat = getValidationTextureFormat(format);
+ if (!validationFormat)
+ SLANG_CHECK_ABORT(false);
+
+ ShaderAndUnorderedTests test;
+ test.init(device, context, format, validationFormat, view, shape);
+ test.run();
+ }
+ }
+ }
+
+ void renderTargetTestImpl(IDevice* device, UnitTestContext* context)
+ {
+ // TODO: Buffer and TextureCube
+ for (Int i = 2; i < (int32_t)IResource::Type::TextureCube; ++i)
+ {
+ auto shape = (IResource::Type)i;
+ auto view = IResourceView::Type::RenderTarget;
+ auto format = Format::R32G32B32A32_FLOAT;
+ auto validationFormat = getValidationTextureFormat(format);
+ if (!validationFormat)
+ SLANG_CHECK_ABORT(false);
+
+ RenderTargetTests test;
+ test.init(device, context, format, validationFormat, view, shape);
+ test.run();
+ }
+ }
+
+ SLANG_UNIT_TEST(shaderAndUnorderedAccessTests)
+ {
+ runTestImpl(shaderAndUnorderedTestImpl, unitTestContext, Slang::RenderApiFlag::D3D12);
+ runTestImpl(shaderAndUnorderedTestImpl, unitTestContext, Slang::RenderApiFlag::Vulkan);
+ }
+
+ SLANG_UNIT_TEST(renderTargetTests)
+ {
+ runTestImpl(renderTargetTestImpl, unitTestContext, Slang::RenderApiFlag::D3D12);
+ runTestImpl(renderTargetTestImpl, unitTestContext, Slang::RenderApiFlag::Vulkan);
+ }
+}
+
+// 1D + array + multisample, ditto for 2D, ditto for 3D
+// one test with something bound, one test with nothing bound, one test with subset of layers (set values in SubresourceRange and assign in desc)
diff --git a/tools/gfx-unit-test/trivial-copy-textures.slang b/tools/gfx-unit-test/trivial-copy-textures.slang
new file mode 100644
index 000000000..8caebd4f9
--- /dev/null
+++ b/tools/gfx-unit-test/trivial-copy-textures.slang
@@ -0,0 +1,303 @@
+// trivial-copy-textures.slang
+
+typedef uint4 Element;
+
+// UNORDERED ACCESS VIEW
+[shader("compute")]
+[numthreads(1,1,1)]
+void resourceViewTest3DUnordered(
+ uint3 sv_dispatchThreadID : SV_DispatchThreadID,
+ uniform uint width,
+ uniform uint height,
+ uniform uint depth,
+ uniform RWTexture3D<Element> resourceView,
+ uniform RWStructuredBuffer<Element> testResults)
+{
+ uint tid = sv_dispatchThreadID.x;
+
+ uint tmp = tid;
+ uint x = tmp % width; tmp /= width;
+ uint y = tmp % height; tmp /= height;
+ uint z = tmp;
+
+ uint3 coord = uint3(x, y, z);
+
+ // Read from resourceView
+ Element elem = resourceView[coord];
+
+ // Write to resourceView (if possible)
+ resourceView[coord] = Element(1);
+
+ // Write something to testResults
+ testResults[tid] = elem;
+}
+
+[shader("compute")]
+[numthreads(1,1,1)]
+void resourceViewTest2DUnordered(
+ uint3 sv_dispatchThreadID : SV_DispatchThreadID,
+ uniform uint width,
+ uniform uint height,
+ uniform uint depth,
+ uniform RWTexture2D<Element> resourceView,
+ uniform RWStructuredBuffer<Element> testResults)
+{
+ uint tid = sv_dispatchThreadID.x;
+
+ uint tmp = tid;
+ uint x = tmp % width; tmp /= width;
+ uint y = tmp % height; tmp /= height;
+ uint z = tmp;
+
+ uint3 coord = uint3(x, y, z);
+
+ // Read from resourceView
+ Element elem = resourceView[coord.xy];
+
+ // Write to resourceView (if possible)
+ resourceView[coord.xy] = Element(1);
+
+ // Write something to testResults
+ testResults[tid] = elem;
+}
+
+[shader("compute")]
+[numthreads(1,1,1)]
+void resourceViewTest1DUnordered(
+ uint3 sv_dispatchThreadID : SV_DispatchThreadID,
+ uniform uint width,
+ uniform uint height,
+ uniform uint depth,
+ uniform RWTexture1D<Element> resourceView,
+ uniform RWStructuredBuffer<Element> testResults)
+{
+ uint tid = sv_dispatchThreadID.x;
+
+ uint tmp = tid;
+ uint x = tmp % width; tmp /= width;
+ uint y = tmp % height; tmp /= height;
+ uint z = tmp;
+
+ uint3 coord = uint3(x, y, z);
+
+ // Read from resourceView
+ Element elem = resourceView[coord.x];
+
+ // Write to resourceView (if possible)
+ resourceView[coord.x] = Element(1);
+
+ // Write something to testResults
+ testResults[tid] = elem;
+}
+
+// SHADER RESOURCE VIEW
+[shader("compute")]
+[numthreads(1,1,1)]
+void resourceViewTest3DShader(
+ uint3 sv_dispatchThreadID : SV_DispatchThreadID,
+ uniform uint width,
+ uniform uint height,
+ uniform uint depth,
+ uniform Texture3D<Element> resourceView,
+ uniform RWStructuredBuffer<Element> testResults)
+{
+ uint tid = sv_dispatchThreadID.x;
+
+ uint tmp = tid;
+ uint x = tmp % width; tmp /= width;
+ uint y = tmp % height; tmp /= height;
+ uint z = tmp;
+
+ uint3 coord = uint3(x, y, z);
+
+ // Read from resourceView
+ Element elem = resourceView[coord];
+
+ // Write something to testResults
+ testResults[tid] = elem;
+}
+
+[shader("compute")]
+[numthreads(1,1,1)]
+void resourceViewTest2DShader(
+ uint3 sv_dispatchThreadID : SV_DispatchThreadID,
+ uniform uint width,
+ uniform uint height,
+ uniform uint depth,
+ uniform Texture2D<Element> resourceView,
+ uniform RWStructuredBuffer<Element> testResults)
+{
+ uint tid = sv_dispatchThreadID.x;
+
+ uint tmp = tid;
+ uint x = tmp % width; tmp /= width;
+ uint y = tmp % height; tmp /= height;
+ uint z = tmp;
+
+ uint3 coord = uint3(x, y, z);
+
+ // Read from resourceView
+ Element elem = resourceView[coord.xy];
+
+ // Write something to testResults
+ testResults[tid] = elem;
+}
+
+[shader("compute")]
+[numthreads(1,1,1)]
+void resourceViewTest1DShader(
+ uint3 sv_dispatchThreadID : SV_DispatchThreadID,
+ uniform uint width,
+ uniform uint height,
+ uniform uint depth,
+ uniform Texture1D<Element> resourceView,
+ uniform RWStructuredBuffer<Element> testResults)
+{
+ uint tid = sv_dispatchThreadID.x;
+
+ uint tmp = tid;
+ uint x = tmp % width; tmp /= width;
+ uint y = tmp % height; tmp /= height;
+ uint z = tmp;
+
+ uint3 coord = uint3(x, y, z);
+
+ // Read from resourceView
+ Element elem = resourceView[coord.x];
+
+ // Write something to testResults
+ testResults[tid] = elem;
+}
+
+// RENDER TARGET AND DEPTH STENCIL VIEWS
+// Per-vertex attributes to be assembled from bound vertex buffers.
+struct AssembledVertex
+{
+ float3 position : POSITION;
+ float3 color : COLOR;
+};
+
+// Output of the vertex shader, and input to the fragment shader.
+struct CoarseVertex
+{
+ float3 color;
+};
+
+// Output of the fragment shader
+struct Fragment
+{
+ float4 color;
+};
+
+// Vertex Shader
+
+struct VertexStageOutput
+{
+ CoarseVertex coarseVertex : CoarseVertex;
+ float4 sv_position : SV_Position;
+};
+
+[shader("vertex")]
+VertexStageOutput vertexMain(
+ AssembledVertex assembledVertex)
+{
+ VertexStageOutput output;
+
+ float3 position = assembledVertex.position;
+ float3 color = assembledVertex.color;
+
+ output.coarseVertex.color = color;
+ output.sv_position = float4(position, 1.0);
+
+ return output;
+}
+
+// Fragment Shader
+
+[shader("fragment")]
+float4 fragmentMain() : SV_Target
+{
+ return float4(1.0, 2.0, 3.0, 4.0);
+}
+
+
+#if 0
+typedef uint4 Element;
+
+interface ITestCase
+{
+ Element doTest(uint3 coord);
+}
+
+// 1D + array, 2D + array + multisample + multisample array, cube + array
+
+struct UAV_3D : ITestCase
+{
+ uniform RWTexture3D<Element> resourceView,
+
+ Element doTest(uint3 coord)
+ {
+ // Read from resourceView
+ Element elem = resourceView[coord];
+
+ // Write to resourceView (if possible)
+ resourceView[coord] = Element(1);
+
+ return elem;
+ }
+}
+
+struct UAV_2D : ITestCase
+{
+ uniform RWTexture2D<Element> resourceView,
+
+ Element doTest(uint3 coord)
+ {
+ // Read from resourceView
+ Element elem = resourceView[coord.xy];
+
+ // Write to resourceView (if possible)
+ resourceView[coord.xy] = Element(1);
+
+ return elem;
+ }
+}
+
+struct SRV_3D : ITestCase
+{
+ uniform Texture3D<Element> resourceView,
+
+ Element doTest(uint3 coord)
+ {
+ // Read from resourceView
+ Element elem = resourceView[coord];
+
+ return elem;
+ }
+}
+
+// Copy the contents of "src" into "dst". These are for 2D textures containing UINT data.
+[shader("compute")]
+[numthreads(1,1,1)]
+void resourceViewTest<T:ITestCase>(
+ uint3 sv_dispatchThreadID : SV_DispatchThreadID,
+ uniform uint width,
+ uniform uint height,
+ uniform uint depth,
+ uniform T testCase,
+ uniform RWStructuredBuffer<Element> testResults)
+{
+ uint tid = sv_dispatchThreadID.x;
+
+ uint tmp = tid;
+ uint x = tmp % width; tmp /= width;
+ uint y = tmp % height; tmp /= height;
+ uint z = tmp;
+
+ uint3 coord = uint3(x, y, z);
+ Element elem = testCase.doTest(coord);
+
+ // Write something to testResults
+ testResults[tid] = elem;
+}
+#endif
diff --git a/tools/gfx/d3d12/render-d3d12.cpp b/tools/gfx/d3d12/render-d3d12.cpp
index a5b584349..657769284 100644
--- a/tools/gfx/d3d12/render-d3d12.cpp
+++ b/tools/gfx/d3d12/render-d3d12.cpp
@@ -668,7 +668,7 @@ Result DeviceImpl::captureTextureToSurface(
size_t rowPitch = int(desc.Width) * bytesPerPixel;
static const size_t align = 256; // D3D requires minimum 256 byte alignment for texture data.
rowPitch = (rowPitch + align - 1) & ~(align - 1); // Bit trick for rounding up
- size_t bufferSize = rowPitch * int(desc.Height);
+ size_t bufferSize = rowPitch * int(desc.Height) * int(desc.DepthOrArraySize);
if (outRowPitch)
*outRowPitch = rowPitch;
if (outPixelSize)
@@ -717,7 +717,7 @@ Result DeviceImpl::captureTextureToSurface(
dstLoc.PlacedFootprint.Footprint.Format = desc.Format;
dstLoc.PlacedFootprint.Footprint.Width = UINT(desc.Width);
dstLoc.PlacedFootprint.Footprint.Height = UINT(desc.Height);
- dstLoc.PlacedFootprint.Footprint.Depth = 1;
+ dstLoc.PlacedFootprint.Footprint.Depth = UINT(desc.DepthOrArraySize);
dstLoc.PlacedFootprint.Footprint.RowPitch = UINT(rowPitch);
encodeInfo.d3dCommandList->CopyTextureRegion(&dstLoc, 0, 0, 0, &srcLoc, nullptr);
@@ -1749,7 +1749,7 @@ Result DeviceImpl::createTextureView(
rtvDesc.ViewDimension = D3D12_RTV_DIMENSION_TEXTURE3D;
rtvDesc.Texture3D.MipSlice = desc.subresourceRange.mipLevel;
rtvDesc.Texture3D.FirstWSlice = desc.subresourceRange.baseArrayLayer;
- rtvDesc.Texture3D.WSize = desc.subresourceRange.layerCount;
+ rtvDesc.Texture3D.WSize = (desc.subresourceRange.layerCount == 0) ? -1 : desc.subresourceRange.layerCount;
break;
case IResource::Type::Buffer:
rtvDesc.ViewDimension = D3D12_RTV_DIMENSION_BUFFER;
diff --git a/tools/gfx/vulkan/render-vk.cpp b/tools/gfx/vulkan/render-vk.cpp
index 5d4f046b2..f9faddf3d 100644
--- a/tools/gfx/vulkan/render-vk.cpp
+++ b/tools/gfx/vulkan/render-vk.cpp
@@ -3187,7 +3187,7 @@ Result FramebufferImpl::init(DeviceImpl* renderer, const IFramebuffer::Desc& des
auto size = resourceDesc->size;
m_width = getMipLevelSize(viewDesc->subresourceRange.mipLevel, size.width);
m_height = getMipLevelSize(viewDesc->subresourceRange.mipLevel, size.height);
- layerCount = viewDesc->subresourceRange.layerCount;
+ layerCount = (resourceDesc->type == IResource::Type::Texture3D) ? size.depth : viewDesc->subresourceRange.layerCount;
}
else
{