diff --git a/renderdoc/data/glsl/gl_texsample.h b/renderdoc/data/glsl/gl_texsample.h index 6cae9f5fa..0ede44400 100644 --- a/renderdoc/data/glsl/gl_texsample.h +++ b/renderdoc/data/glsl/gl_texsample.h @@ -104,7 +104,7 @@ uvec4 SampleTextureUInt4(int type, vec2 pos, float slice, int mipLevel, int samp } else // if (type == RESTYPE_TEX3D) { - col = texelFetch(texUInt3D, ivec3(pos * texRes.xy, slice + 0.001f), mipLevel); + col = texelFetch(texUInt3D, ivec3(pos * texRes.xy, slice), mipLevel); } return col; @@ -195,7 +195,7 @@ ivec4 SampleTextureSInt4(int type, vec2 pos, float slice, int mipLevel, int samp } else // if (type == RESTYPE_TEX3D) { - col = texelFetch(texSInt3D, ivec3(pos * texRes.xy, slice + 0.001f), mipLevel); + col = texelFetch(texSInt3D, ivec3(pos * texRes.xy, slice), mipLevel); } return col; @@ -377,7 +377,7 @@ vec4 SampleTextureFloat4(int type, vec2 pos, float slice, int mipLevel, int samp } else if(type == RESTYPE_TEX3D) { - col = textureLod(tex3D, vec3(pos, (slice + 0.001f) / texRes.z), float(mipLevel)); + col = textureLod(tex3D, vec3(pos, slice / texRes.z), float(mipLevel)); } else if(type == RESTYPE_TEXCUBE) { diff --git a/renderdoc/data/glsl/gles_texsample.h b/renderdoc/data/glsl/gles_texsample.h index b0584a56e..ac2bee63a 100644 --- a/renderdoc/data/glsl/gles_texsample.h +++ b/renderdoc/data/glsl/gles_texsample.h @@ -109,7 +109,7 @@ uvec4 SampleTextureUInt4(int type, vec2 pos, float slice, int mipLevel, int samp } else // if (type == RESTYPE_TEX3D) { - col = texelFetch(texUInt3D, ivec3(pos * texRes.xy, slice + 0.001f), mipLevel); + col = texelFetch(texUInt3D, ivec3(pos * texRes.xy, slice), mipLevel); } return col; @@ -196,7 +196,7 @@ ivec4 SampleTextureSInt4(int type, vec2 pos, float slice, int mipLevel, int samp } else // if (type == RESTYPE_TEX3D) { - col = texelFetch(texSInt3D, ivec3(pos * texRes.xy, slice + 0.001f), mipLevel); + col = texelFetch(texSInt3D, ivec3(pos * texRes.xy, slice), mipLevel); } return col; @@ -376,7 +376,7 @@ vec4 SampleTextureFloat4(int type, vec2 pos, float slice, int mipLevel, int samp } else if(type == RESTYPE_TEX3D) { - col = textureLod(tex3D, vec3(pos, (slice + 0.001f) / texRes.z), float(mipLevel)); + col = textureLod(tex3D, vec3(pos, slice / texRes.z), float(mipLevel)); } else if(type == RESTYPE_TEXCUBE) { diff --git a/renderdoc/data/glsl/vk_texsample.h b/renderdoc/data/glsl/vk_texsample.h index 65c4eb5c8..9264cd45a 100644 --- a/renderdoc/data/glsl/vk_texsample.h +++ b/renderdoc/data/glsl/vk_texsample.h @@ -65,7 +65,7 @@ vec4 SampleTextureFloat4(int type, vec2 pos, float slice, int mipLevel, int samp } else if(type == RESTYPE_TEX3D) { - col = textureLod(tex3D, vec3(pos, (slice + 0.001f) / texRes.z), float(mipLevel)); + col = textureLod(tex3D, vec3(pos, slice / texRes.z), float(mipLevel)); } else if(type == RESTYPE_TEX2DMS) { @@ -196,7 +196,7 @@ uvec4 SampleTextureUInt4(int type, vec2 pos, float slice, int mipLevel, int samp } else if(type == RESTYPE_TEX3D) { - col = texelFetch(texUInt3D, ivec3(pos * texRes.xy, slice + 0.001f), mipLevel); + col = texelFetch(texUInt3D, ivec3(pos * texRes.xy, slice), mipLevel); } else if(type == RESTYPE_TEX2DMS) { @@ -251,7 +251,7 @@ ivec4 SampleTextureSInt4(int type, vec2 pos, float slice, int mipLevel, int samp } else if(type == RESTYPE_TEX3D) { - col = texelFetch(texSInt3D, ivec3(pos * texRes.xy, slice + 0.001f), mipLevel); + col = texelFetch(texSInt3D, ivec3(pos * texRes.xy, slice), mipLevel); } else if(type == RESTYPE_TEX2DMS) { diff --git a/renderdoc/data/hlsl/hlsl_texsample.h b/renderdoc/data/hlsl/hlsl_texsample.h index 2ddb4118c..47bce8bd0 100644 --- a/renderdoc/data/hlsl/hlsl_texsample.h +++ b/renderdoc/data/hlsl/hlsl_texsample.h @@ -56,7 +56,7 @@ uint4 SampleTextureUInt4(uint type, float2 uv, float slice, float mip, int sampl if(type == RESTYPE_TEX1D) col = texDisplayUIntTex1DArray.Load(int3(uv.x * texRes.x, slice, mip)); else if(type == RESTYPE_TEX3D) - col = texDisplayUIntTex3D.Load(int4(uv.xy * texRes.xy, slice + 0.001f, mip)); + col = texDisplayUIntTex3D.Load(int4(uv.xy * texRes.xy, slice, mip)); else if(type == RESTYPE_TEX2D) col = texDisplayUIntTex2DArray.Load(int4(uv.xy * texRes.xy, slice, mip)); else if(type == RESTYPE_TEX2D_MS) @@ -76,7 +76,7 @@ int4 SampleTextureInt4(uint type, float2 uv, float slice, float mip, int sample, if(type == RESTYPE_TEX1D) col = texDisplayIntTex1DArray.Load(int3(uv.x * texRes.x, slice, mip)); else if(type == RESTYPE_TEX3D) - col = texDisplayIntTex3D.Load(int4(uv.xy * texRes.xy, slice + 0.001f, mip)); + col = texDisplayIntTex3D.Load(int4(uv.xy * texRes.xy, slice, mip)); else if(type == RESTYPE_TEX2D) col = texDisplayIntTex2DArray.Load(int4(uv.xy * texRes.xy, slice, mip)); else if(type == RESTYPE_TEX2D_MS) @@ -117,10 +117,9 @@ float4 SampleTextureFloat4(uint type, bool linearSample, float2 uv, float slice, else if(type == RESTYPE_TEX3D) { if(linearSample) - col = texDisplayTex3D.SampleLevel(linearSampler, float3(uv.xy, (slice + 0.001f) / texRes.z), - mip); + col = texDisplayTex3D.SampleLevel(linearSampler, float3(uv.xy, slice / texRes.z), mip); else - col = texDisplayTex3D.Load(int4(uv.xy * texRes.xy, slice + 0.001f, mip)); + col = texDisplayTex3D.Load(int4(uv.xy * texRes.xy, slice, mip)); } else if(type == RESTYPE_DEPTH) { diff --git a/renderdoc/driver/d3d11/d3d11_rendertexture.cpp b/renderdoc/driver/d3d11/d3d11_rendertexture.cpp index e74416fdc..d9253eab3 100644 --- a/renderdoc/driver/d3d11/d3d11_rendertexture.cpp +++ b/renderdoc/driver/d3d11/d3d11_rendertexture.cpp @@ -724,8 +724,18 @@ bool D3D11Replay::RenderTextureInternal(TextureDisplay cfg, TexDisplayFlags flag if(details.texType == eTexType_3D) { pixelData.OutputDisplayFormat = RESTYPE_TEX3D; - pixelData.Slice = float( - RDCCLAMP(cfg.subresource.slice, 0U, (details.texDepth >> cfg.subresource.mip) - 1) + 0.001f); + float slice = + float(RDCCLAMP(cfg.subresource.slice, 0U, (details.texDepth >> cfg.subresource.mip) - 1)); + + // when sampling linearly, we need to add half a pixel to ensure we only sample the desired + // slice + if(cfg.subresource.mip == 0 && cfg.scale < 1.0f && !IsUIntFormat(details.srvFormat) && + !IsIntFormat(details.srvFormat)) + slice += 0.5f; + else + slice += 0.001f; + + pixelData.Slice = slice; } else if(details.texType == eTexType_1D) { diff --git a/renderdoc/driver/d3d12/d3d12_rendertexture.cpp b/renderdoc/driver/d3d12/d3d12_rendertexture.cpp index 3714be5cd..d6f63c554 100644 --- a/renderdoc/driver/d3d12/d3d12_rendertexture.cpp +++ b/renderdoc/driver/d3d12/d3d12_rendertexture.cpp @@ -449,14 +449,28 @@ bool D3D12Replay::RenderTextureInternal(D3D12_CPU_DESCRIPTOR_HANDLE rtv, Texture pixelData.MipLevel = (float)cfg.subresource.mip; + DXGI_FORMAT fmt = GetTypedFormat(resourceDesc.Format, cfg.typeCast); + if(resourceDesc.Dimension == D3D12_RESOURCE_DIMENSION_TEXTURE3D) - pixelData.Slice = + { + float slice = float(RDCCLAMP(cfg.subresource.slice, 0U, - uint32_t((resourceDesc.DepthOrArraySize >> cfg.subresource.mip) - 1)) + - 0.001f); + uint32_t((resourceDesc.DepthOrArraySize >> cfg.subresource.mip) - 1))); + + // when sampling linearly, we need to add half a pixel to ensure we only sample the desired + // slice + if(cfg.subresource.mip == 0 && cfg.scale < 1.0f && !IsUIntFormat(fmt) && !IsIntFormat(fmt)) + slice += 0.5f; + else + slice += 0.001f; + + pixelData.Slice = slice; + } else + { pixelData.Slice = float( RDCCLAMP(cfg.subresource.slice, 0U, uint32_t(resourceDesc.DepthOrArraySize - 1)) + 0.001f); + } rdcarray barriers; int resType = 0; @@ -470,8 +484,6 @@ bool D3D12Replay::RenderTextureInternal(D3D12_CPU_DESCRIPTOR_HANDLE rtv, Texture if(cfg.overlay == DebugOverlay::Clipping) pixelData.OutputDisplayFormat |= TEXDISPLAY_CLIPPING; - DXGI_FORMAT fmt = GetTypedFormat(resourceDesc.Format, cfg.typeCast); - if(IsUIntFormat(fmt)) pixelData.OutputDisplayFormat |= TEXDISPLAY_UINT_TEX; else if(IsIntFormat(fmt)) diff --git a/renderdoc/driver/gl/gl_rendertexture.cpp b/renderdoc/driver/gl/gl_rendertexture.cpp index 29d550012..99febac31 100644 --- a/renderdoc/driver/gl/gl_rendertexture.cpp +++ b/renderdoc/driver/gl/gl_rendertexture.cpp @@ -535,6 +535,22 @@ bool GLReplay::RenderTextureInternal(TextureDisplay cfg, TexDisplayFlags flags) ubo->RangeMinimum = cfg.rangeMin; ubo->InverseRangeSize = 1.0f / (cfg.rangeMax - cfg.rangeMin); + TextureSamplerMode mode = TextureSamplerMode::Point; + + if(cfg.subresource.mip == 0 && cfg.scale < 1.0f && dsTexMode == eGL_NONE && + resType != RESTYPE_TEXBUFFER && resType != RESTYPE_TEXRECT && !intTexture) + { + mode = TextureSamplerMode::Linear; + } + else + { + if(resType == RESTYPE_TEXRECT || resType == RESTYPE_TEX2DMS || + resType == RESTYPE_TEX2DMSARRAY || resType == RESTYPE_TEXBUFFER) + mode = TextureSamplerMode::PointNoMip; + else + mode = TextureSamplerMode::Point; + } + ubo->MipLevel = (int)cfg.subresource.mip; if(texDetails.curType != eGL_TEXTURE_3D) { @@ -550,9 +566,17 @@ bool GLReplay::RenderTextureInternal(TextureDisplay cfg, TexDisplayFlags flags) } else { - uint32_t sliceFace = - RDCCLAMP(cfg.subresource.slice, 0U, RDCMAX((uint32_t)texDetails.depth, 1U) - 1); - ubo->Slice = (float)sliceFace + 0.001f; + float slice = + (float)RDCCLAMP(cfg.subresource.slice, 0U, RDCMAX((uint32_t)texDetails.depth, 1U) - 1); + + // when sampling linearly, we need to add half a pixel to ensure we only sample the desired + // slice + if(mode == TextureSamplerMode::Linear) + slice += 0.5f; + else + slice += 0.001f; + + ubo->Slice = slice; } ubo->OutputDisplayFormat = resType; @@ -592,22 +616,6 @@ bool GLReplay::RenderTextureInternal(TextureDisplay cfg, TexDisplayFlags flags) drv.glUnmapBuffer(eGL_UNIFORM_BUFFER); - TextureSamplerMode mode = TextureSamplerMode::Point; - - if(cfg.subresource.mip == 0 && cfg.scale < 1.0f && dsTexMode == eGL_NONE && - resType != RESTYPE_TEXBUFFER && resType != RESTYPE_TEXRECT && !intTexture) - { - mode = TextureSamplerMode::Linear; - } - else - { - if(resType == RESTYPE_TEXRECT || resType == RESTYPE_TEX2DMS || - resType == RESTYPE_TEX2DMSARRAY || resType == RESTYPE_TEXBUFFER) - mode = TextureSamplerMode::PointNoMip; - else - mode = TextureSamplerMode::Point; - } - TextureSamplerState prevSampState = SetSamplerParams(target, texname, mode); HeatmapData heatmapData = {}; diff --git a/renderdoc/driver/vulkan/vk_rendertexture.cpp b/renderdoc/driver/vulkan/vk_rendertexture.cpp index 48c4237d6..03a7e7841 100644 --- a/renderdoc/driver/vulkan/vk_rendertexture.cpp +++ b/renderdoc/driver/vulkan/vk_rendertexture.cpp @@ -293,8 +293,17 @@ bool VulkanReplay::RenderTextureInternal(TextureDisplay cfg, const ImageState &i } else { - uint32_t sliceFace = RDCCLAMP(cfg.subresource.slice, 0U, iminfo.extent.depth - 1); - data->Slice = (float)sliceFace + 0.001f; + float slice = (float)RDCCLAMP(cfg.subresource.slice, 0U, iminfo.extent.depth - 1); + + // when sampling linearly, we need to add half a pixel to ensure we only sample the desired + // slice + if(cfg.subresource.mip == 0 && cfg.scale < 1.0f && + (displayformat & (TEXDISPLAY_UINT_TEX | TEXDISPLAY_SINT_TEX)) == 0) + slice += 0.5f; + else + slice += 0.001f; + + data->Slice = slice; } data->TextureResolutionPS.x = float(RDCMAX(1, tex_x >> cfg.subresource.mip)); diff --git a/util/test/demos/d3d11/d3d11_texture_zoo.cpp b/util/test/demos/d3d11/d3d11_texture_zoo.cpp index 556e60ccf..fa4995614 100644 --- a/util/test/demos/d3d11/d3d11_texture_zoo.cpp +++ b/util/test/demos/d3d11/d3d11_texture_zoo.cpp @@ -1026,6 +1026,46 @@ int4 main(float4 pos : SV_Position, uint samp : SV_SampleIndex) : SV_Target0 ds.StencilEnable = FALSE; SetDepthState(ds); + std::vector blue; + blue.resize(64 * 64 * 64, Vec4f(0.0f, 0.0f, 1.0f, 1.0f)); + + std::vector green; + green.resize(64 * 64, Vec4f(0.0f, 1.0f, 0.0f, 1.0f)); + + // slice testing textures + + TestCase slice_test_array = {}; + TestCase slice_test_3d = {}; + slice_test_array.res = + (ID3D11Texture2DPtr)MakeTexture(DXGI_FORMAT_R32G32B32A32_FLOAT, 64, 64).Array(64).Mips(2).SRV(); + slice_test_array.srv = MakeSRV((ID3D11Texture2DPtr)slice_test_array.res); + slice_test_array.dim = 2; + slice_test_array.isArray = true; + + for(UINT slice = 0; slice < 64; slice++) + { + ctx->UpdateSubresource(slice_test_array.res, slice * 2, NULL, + slice == 17 ? green.data() : blue.data(), 64 * 4, 64 * 64 * 4); + ctx->UpdateSubresource(slice_test_array.res, slice * 2 + 1, NULL, + slice == 17 ? green.data() : blue.data(), 32 * 4, 32 * 32 * 4); + } + + slice_test_3d.res = + (ID3D11Texture3DPtr)MakeTexture(DXGI_FORMAT_R32G32B32A32_FLOAT, 64, 64, 64).Mips(2).SRV(); + slice_test_3d.srv = MakeSRV((ID3D11Texture3DPtr)slice_test_3d.res); + slice_test_3d.dim = 3; + + ctx->UpdateSubresource(slice_test_3d.res, 0, NULL, blue.data(), 64 * 4, 64 * 64 * 4); + ctx->UpdateSubresource(slice_test_3d.res, 1, NULL, blue.data(), 32 * 4, 32 * 32 * 4); + + D3D11_BOX box = {}; + box.right = box.bottom = 64; + box.front = 17; + box.back = 18; + ctx->UpdateSubresource(slice_test_3d.res, 0, &box, green.data(), 64 * 4, 64 * 64 * 4); + box.right = box.bottom = 32; + ctx->UpdateSubresource(slice_test_3d.res, 1, &box, green.data(), 32 * 4, 32 * 32 * 4); + while(Running()) { ctx->ClearState(); @@ -1043,6 +1083,21 @@ int4 main(float4 pos : SV_Position, uint samp : SV_SampleIndex) : SV_Target0 rs.ScissorEnable = TRUE; SetRasterState(rs); + RSSetViewport(view); + + // dummy draw for each slice test texture + pushMarker("slice tests"); + setMarker("2D array"); + ctx->PSSetShader(GetShader(slice_test_array), NULL, 0); + ctx->PSSetShaderResources(0, 1, &slice_test_array.srv.GetInterfacePtr()); + ctx->Draw(0, 0); + + setMarker("3D"); + ctx->PSSetShader(GetShader(slice_test_3d), NULL, 0); + ctx->PSSetShaderResources(0, 1, &slice_test_3d.srv.GetInterfacePtr()); + ctx->Draw(0, 0); + popMarker(); + for(size_t i = 0; i < test_textures.size(); i++) { if(i == 0 || test_textures[i].fmt.texFmt != test_textures[i - 1].fmt.texFmt || diff --git a/util/test/demos/d3d12/d3d12_texture_zoo.cpp b/util/test/demos/d3d12/d3d12_texture_zoo.cpp index d5ed34d5c..cdaaed579 100644 --- a/util/test/demos/d3d12/d3d12_texture_zoo.cpp +++ b/util/test/demos/d3d12/d3d12_texture_zoo.cpp @@ -635,7 +635,7 @@ int4 main(float4 pos : SV_Position, uint samp : SV_SampleIndex) : SV_Target0 ID3D12PipelineStatePtr blitpso = MakePSO().RootSig(sig).VS(vsblob).PS(psblob); - uploadBuf = MakeBuffer().Upload().Size(1024 * 1024); + uploadBuf = MakeBuffer().Upload().Size(8 * 1024 * 1024); CurBuf = Map(uploadBuf, 0); @@ -1119,6 +1119,110 @@ int4 main(float4 pos : SV_Position, uint samp : SV_SampleIndex) : SV_Target0 GPUSync(); } + std::vector blue; + blue.resize(64 * 64 * 64, Vec4f(0.0f, 0.0f, 1.0f, 1.0f)); + + std::vector green; + green.resize(64 * 64, Vec4f(0.0f, 1.0f, 0.0f, 1.0f)); + + CurBuf = Map(uploadBuf, 0); + + memcpy(CurBuf, blue.data(), blue.size() * sizeof(Vec4f)); + memcpy(CurBuf + blue.size() * sizeof(Vec4f), green.data(), green.size() * sizeof(Vec4f)); + + uploadBuf->Unmap(0, NULL); + + // slice testing textures + + TestCase slice_test_array = {}; + TestCase slice_test_3d = {}; + slice_test_array.dim = 2; + slice_test_array.isArray = true; + slice_test_array.res = MakeTexture(DXGI_FORMAT_R32G32B32A32_FLOAT, 64, 64).Array(64).Mips(2); + slice_test_array.srv = MakeSRV(slice_test_array.res).CreateGPU(srvIndex++); + + slice_test_3d.dim = 3; + slice_test_3d.res = MakeTexture(DXGI_FORMAT_R32G32B32A32_FLOAT, 64, 64, 64).Mips(2); + slice_test_3d.srv = MakeSRV(slice_test_3d.res).CreateGPU(srvIndex++); + + { + ID3D12GraphicsCommandListPtr cmd = GetCommandBuffer(); + + Reset(cmd); + + ResourceBarrier(cmd, slice_test_array.res, D3D12_RESOURCE_STATE_COMMON, + D3D12_RESOURCE_STATE_COPY_DEST); + ResourceBarrier(cmd, slice_test_3d.res, D3D12_RESOURCE_STATE_COMMON, + D3D12_RESOURCE_STATE_COPY_DEST); + + for(UINT s = 0; s < 64; s++) + { + for(UINT m = 0; m < 2; m++) + { + D3D12_TEXTURE_COPY_LOCATION dst = {}; + D3D12_TEXTURE_COPY_LOCATION src = {}; + + dst.Type = D3D12_TEXTURE_COPY_TYPE_SUBRESOURCE_INDEX; + dst.pResource = slice_test_array.res; + dst.SubresourceIndex = s * 2 + m; + + src.Type = D3D12_TEXTURE_COPY_TYPE_PLACED_FOOTPRINT; + src.pResource = uploadBuf; + src.PlacedFootprint.Footprint.Format = DXGI_FORMAT_R32G32B32A32_FLOAT; + src.PlacedFootprint.Footprint.RowPitch = (64 >> m) * sizeof(Vec4f); + src.PlacedFootprint.Footprint.Width = 64 >> m; + src.PlacedFootprint.Footprint.Height = 64 >> m; + src.PlacedFootprint.Footprint.Depth = 1; + + if(s == 17) + src.PlacedFootprint.Offset = blue.size() * sizeof(Vec4f); + + cmd->CopyTextureRegion(&dst, 0, 0, 0, &src, NULL); + + if(s == 0) + { + dst.pResource = slice_test_3d.res; + dst.SubresourceIndex = m; + src.PlacedFootprint.Footprint.Depth = 64 >> m; + + cmd->CopyTextureRegion(&dst, 0, 0, 0, &src, NULL); + } + } + } + + for(int m = 0; m < 2; m++) + { + D3D12_TEXTURE_COPY_LOCATION dst = {}; + D3D12_TEXTURE_COPY_LOCATION src = {}; + + dst.Type = D3D12_TEXTURE_COPY_TYPE_SUBRESOURCE_INDEX; + dst.pResource = slice_test_3d.res; + dst.SubresourceIndex = m; + + src.Type = D3D12_TEXTURE_COPY_TYPE_PLACED_FOOTPRINT; + src.pResource = uploadBuf; + src.PlacedFootprint.Footprint.Format = DXGI_FORMAT_R32G32B32A32_FLOAT; + src.PlacedFootprint.Footprint.RowPitch = (64 >> m) * sizeof(Vec4f); + src.PlacedFootprint.Footprint.Width = 64 >> m; + src.PlacedFootprint.Footprint.Height = 64 >> m; + src.PlacedFootprint.Footprint.Depth = 1; + src.PlacedFootprint.Offset = blue.size() * sizeof(Vec4f); + + cmd->CopyTextureRegion(&dst, 0, 0, 17, &src, NULL); + } + + ResourceBarrier(cmd, slice_test_array.res, D3D12_RESOURCE_STATE_COPY_DEST, + D3D12_RESOURCE_STATE_PIXEL_SHADER_RESOURCE); + ResourceBarrier(cmd, slice_test_3d.res, D3D12_RESOURCE_STATE_COPY_DEST, + D3D12_RESOURCE_STATE_PIXEL_SHADER_RESOURCE); + + cmd->Close(); + + Submit({cmd}); + + GPUSync(); + } + while(Running()) { ID3D12GraphicsCommandListPtr cmd = GetCommandBuffer(); @@ -1139,6 +1243,28 @@ int4 main(float4 pos : SV_Position, uint samp : SV_SampleIndex) : SV_Target0 D3D12_VIEWPORT view = {0.0f, 0.0f, 10.0f, 10.0f, 0.0f, 1.0f}; + { + RSSetViewport(cmd, view); + D3D12_RECT rect = { + (LONG)view.TopLeftX, (LONG)view.TopLeftY, LONG(view.TopLeftX + view.Width), + LONG(view.TopLeftY + view.Height), + }; + RSSetScissorRect(cmd, rect); + } + + // dummy draw for each slice test texture + pushMarker(cmd, "slice tests"); + setMarker(cmd, "2D array"); + cmd->SetPipelineState(GetPSO(slice_test_array)); + cmd->SetGraphicsRootDescriptorTable(1, slice_test_array.srv); + cmd->DrawInstanced(0, 0, 0, 0); + + setMarker(cmd, "3D"); + cmd->SetPipelineState(GetPSO(slice_test_3d)); + cmd->SetGraphicsRootDescriptorTable(1, slice_test_3d.srv); + cmd->DrawInstanced(0, 0, 0, 0); + popMarker(cmd); + for(size_t i = 0; i < test_textures.size(); i++) { if(i == 0 || test_textures[i].fmt.texFmt != test_textures[i - 1].fmt.texFmt || diff --git a/util/test/demos/gl/gl_texture_zoo.cpp b/util/test/demos/gl/gl_texture_zoo.cpp index e710528de..3499682fe 100644 --- a/util/test/demos/gl/gl_texture_zoo.cpp +++ b/util/test/demos/gl/gl_texture_zoo.cpp @@ -970,6 +970,35 @@ void main() glTexStorage2D(GL_TEXTURE_2D, 1, GL_RGBA32F, screenWidth, screenHeight); glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, colattach, 0); + std::vector blue; + blue.resize(64 * 64 * 64, Vec4f(0.0f, 0.0f, 1.0f, 1.0f)); + + std::vector green; + green.resize(64 * 64, Vec4f(0.0f, 1.0f, 0.0f, 1.0f)); + + // slice testing textures + + TestCase slice_test_array = {}; + TestCase slice_test_3d = {}; + slice_test_array.tex = MakeTexture(); + slice_test_array.dim = 2; + slice_test_array.isArray = true; + glBindTexture(GL_TEXTURE_2D_ARRAY, slice_test_array.tex); + glTexStorage3D(GL_TEXTURE_2D_ARRAY, 2, GL_RGBA32F, 64, 64, 64); + glTexSubImage3D(GL_TEXTURE_2D_ARRAY, 0, 0, 0, 0, 64, 64, 64, GL_RGBA, GL_FLOAT, blue.data()); + glTexSubImage3D(GL_TEXTURE_2D_ARRAY, 1, 0, 0, 0, 32, 32, 32, GL_RGBA, GL_FLOAT, blue.data()); + glTexSubImage3D(GL_TEXTURE_2D_ARRAY, 0, 0, 0, 17, 64, 64, 1, GL_RGBA, GL_FLOAT, green.data()); + glTexSubImage3D(GL_TEXTURE_2D_ARRAY, 1, 0, 0, 17, 32, 32, 1, GL_RGBA, GL_FLOAT, green.data()); + + slice_test_3d.tex = MakeTexture(); + slice_test_3d.dim = 3; + glBindTexture(GL_TEXTURE_3D, slice_test_3d.tex); + glTexStorage3D(GL_TEXTURE_3D, 2, GL_RGBA32F, 64, 64, 64); + glTexSubImage3D(GL_TEXTURE_3D, 0, 0, 0, 0, 64, 64, 64, GL_RGBA, GL_FLOAT, blue.data()); + glTexSubImage3D(GL_TEXTURE_3D, 1, 0, 0, 0, 32, 32, 32, GL_RGBA, GL_FLOAT, blue.data()); + glTexSubImage3D(GL_TEXTURE_3D, 0, 0, 0, 17, 64, 64, 1, GL_RGBA, GL_FLOAT, green.data()); + glTexSubImage3D(GL_TEXTURE_3D, 1, 0, 0, 17, 32, 32, 1, GL_RGBA, GL_FLOAT, green.data()); + while(Running()) { glBindFramebuffer(GL_FRAMEBUFFER, fbo); @@ -982,6 +1011,19 @@ void main() GLsizei viewX = 0, viewY = screenHeight - 10; glEnable(GL_SCISSOR_TEST); + // dummy draw for each slice test texture + pushMarker("slice tests"); + setMarker("2D array"); + glBindTextureUnit(0, slice_test_array.tex); + glUseProgram(GetProgram(slice_test_array)); + glDrawArrays(GL_TRIANGLES, 0, 0); + + setMarker("3D"); + glBindTextureUnit(0, slice_test_3d.tex); + glUseProgram(GetProgram(slice_test_3d)); + glDrawArrays(GL_TRIANGLES, 0, 0); + popMarker(); + for(size_t i = 0; i < test_textures.size(); i++) { if(i == 0 || test_textures[i].fmt.internalFormat != test_textures[i - 1].fmt.internalFormat) diff --git a/util/test/demos/vk/vk_texture_zoo.cpp b/util/test/demos/vk/vk_texture_zoo.cpp index ebd7ffdfa..cd77f6ec4 100644 --- a/util/test/demos/vk/vk_texture_zoo.cpp +++ b/util/test/demos/vk/vk_texture_zoo.cpp @@ -631,7 +631,7 @@ void main() if(!Init()) return 3; - VkSampler sampler = createSampler(vkh::SamplerCreateInfo(VK_FILTER_LINEAR)); + VkSampler sampler = createSampler(vkh::SamplerCreateInfo(VK_FILTER_NEAREST)); setlayout = createDescriptorSetLayout(vkh::DescriptorSetLayoutCreateInfo({ {0, VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, 1, VK_SHADER_STAGE_FRAGMENT_BIT, &sampler}, @@ -671,9 +671,9 @@ void main() VkFramebuffer framebuffer = createFramebuffer(vkh::FramebufferCreateInfo(rp, {fltView}, mainWindow->scissor.extent)); - uploadBuf = - AllocatedBuffer(this, vkh::BufferCreateInfo(1024 * 1024, VK_BUFFER_USAGE_TRANSFER_SRC_BIT), - VmaAllocationCreateInfo({0, VMA_MEMORY_USAGE_CPU_TO_GPU})); + uploadBuf = AllocatedBuffer( + this, vkh::BufferCreateInfo(8 * 1024 * 1024, VK_BUFFER_USAGE_TRANSFER_SRC_BIT), + VmaAllocationCreateInfo({0, VMA_MEMORY_USAGE_CPU_TO_GPU})); CurBuf = uploadBuf.map(); @@ -1402,6 +1402,151 @@ void main() vkDestroyPipeline(device, pipe, NULL); } + std::vector blue; + blue.resize(64 * 64 * 64, Vec4f(0.0f, 0.0f, 1.0f, 1.0f)); + + std::vector green; + green.resize(64 * 64, Vec4f(0.0f, 1.0f, 0.0f, 1.0f)); + + CurBuf = uploadBuf.map(); + + memcpy(CurBuf, blue.data(), blue.size() * sizeof(Vec4f)); + memcpy(CurBuf + blue.size() * sizeof(Vec4f), green.data(), green.size() * sizeof(Vec4f)); + + uploadBuf.unmap(); + + // slice testing textures + + TestCase slice_test_array = {}; + TestCase slice_test_3d = {}; + slice_test_array.dim = 2; + slice_test_array.isArray = true; + slice_test_array.res = AllocatedImage( + this, + vkh::ImageCreateInfo(64, 64, 0, VK_FORMAT_R32G32B32A32_SFLOAT, + VK_IMAGE_USAGE_SAMPLED_BIT | VK_IMAGE_USAGE_TRANSFER_DST_BIT, 2, 64), + VmaAllocationCreateInfo({0, VMA_MEMORY_USAGE_GPU_ONLY})); + slice_test_array.view = createImageView(vkh::ImageViewCreateInfo( + slice_test_array.res.image, VK_IMAGE_VIEW_TYPE_2D_ARRAY, VK_FORMAT_R32G32B32A32_SFLOAT)); + slice_test_array.set = allocateDescriptorSet(setlayout); + vkh::updateDescriptorSets( + device, { + vkh::WriteDescriptorSet(slice_test_array.set, 0, + VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, + {vkh::DescriptorImageInfo(slice_test_array.view)}), + }); + + slice_test_3d.dim = 3; + slice_test_3d.res = AllocatedImage( + this, vkh::ImageCreateInfo(64, 64, 64, VK_FORMAT_R32G32B32A32_SFLOAT, + VK_IMAGE_USAGE_SAMPLED_BIT | VK_IMAGE_USAGE_TRANSFER_DST_BIT, 2), + VmaAllocationCreateInfo({0, VMA_MEMORY_USAGE_GPU_ONLY})); + slice_test_3d.view = createImageView(vkh::ImageViewCreateInfo( + slice_test_3d.res.image, VK_IMAGE_VIEW_TYPE_3D, VK_FORMAT_R32G32B32A32_SFLOAT)); + slice_test_3d.set = allocateDescriptorSet(setlayout); + vkh::updateDescriptorSets( + device, + { + vkh::WriteDescriptorSet(slice_test_3d.set, 0, VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, + {vkh::DescriptorImageInfo(slice_test_3d.view)}), + }); + + { + VkCommandBuffer cmd = GetCommandBuffer(); + + vkBeginCommandBuffer(cmd, vkh::CommandBufferBeginInfo()); + + vkh::cmdPipelineBarrier( + cmd, + { + vkh::ImageMemoryBarrier(0, VK_ACCESS_TRANSFER_WRITE_BIT, VK_IMAGE_LAYOUT_UNDEFINED, + VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, + slice_test_array.res.image), + vkh::ImageMemoryBarrier(0, VK_ACCESS_TRANSFER_WRITE_BIT, VK_IMAGE_LAYOUT_UNDEFINED, + VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, slice_test_3d.res.image), + }); + + VkBufferImageCopy copy = {}; + copy.imageSubresource.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; + copy.imageExtent = {64, 64, 1}; + copy.imageSubresource.layerCount = 64; + + vkCmdCopyBufferToImage(cmd, uploadBuf.buffer, slice_test_array.res.image, + VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, 1, ©); + + copy.imageExtent.depth = 64; + copy.imageSubresource.layerCount = 1; + vkCmdCopyBufferToImage(cmd, uploadBuf.buffer, slice_test_3d.res.image, + VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, 1, ©); + + copy.imageSubresource.mipLevel = 1; + copy.imageExtent = {32, 32, 1}; + copy.imageSubresource.layerCount = 64; + vkCmdCopyBufferToImage(cmd, uploadBuf.buffer, slice_test_array.res.image, + VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, 1, ©); + + copy.imageExtent.depth = 32; + copy.imageSubresource.layerCount = 1; + vkCmdCopyBufferToImage(cmd, uploadBuf.buffer, slice_test_3d.res.image, + VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, 1, ©); + + vkh::cmdPipelineBarrier( + cmd, + { + vkh::ImageMemoryBarrier(VK_ACCESS_TRANSFER_WRITE_BIT, VK_ACCESS_TRANSFER_WRITE_BIT, + VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, + VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, + slice_test_array.res.image), + vkh::ImageMemoryBarrier(VK_ACCESS_TRANSFER_WRITE_BIT, VK_ACCESS_TRANSFER_WRITE_BIT, + VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, + VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, slice_test_3d.res.image), + }); + + copy.imageSubresource.mipLevel = 0; + copy.imageSubresource.baseArrayLayer = 17; + copy.imageExtent = {64, 64, 1}; + copy.imageSubresource.layerCount = 1; + copy.bufferOffset = blue.size() * sizeof(Vec4f); + + vkCmdCopyBufferToImage(cmd, uploadBuf.buffer, slice_test_array.res.image, + VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, 1, ©); + + copy.imageSubresource.baseArrayLayer = 0; + copy.imageOffset.z = 17; + vkCmdCopyBufferToImage(cmd, uploadBuf.buffer, slice_test_3d.res.image, + VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, 1, ©); + + copy.imageSubresource.mipLevel = 1; + copy.imageExtent = {32, 32, 1}; + copy.imageOffset.z = 0; + copy.imageSubresource.baseArrayLayer = 17; + vkCmdCopyBufferToImage(cmd, uploadBuf.buffer, slice_test_array.res.image, + VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, 1, ©); + + copy.imageSubresource.baseArrayLayer = 0; + copy.imageOffset.z = 17; + vkCmdCopyBufferToImage(cmd, uploadBuf.buffer, slice_test_3d.res.image, + VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, 1, ©); + + vkh::cmdPipelineBarrier( + cmd, { + vkh::ImageMemoryBarrier(VK_ACCESS_TRANSFER_WRITE_BIT, VK_ACCESS_SHADER_READ_BIT, + VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, + VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, + slice_test_array.res.image), + vkh::ImageMemoryBarrier(VK_ACCESS_TRANSFER_WRITE_BIT, VK_ACCESS_SHADER_READ_BIT, + VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, + VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, + slice_test_3d.res.image), + }); + + vkEndCommandBuffer(cmd); + + Submit(99, 99, {cmd}); + + vkDeviceWaitIdle(device); + } + while(Running()) { VkCommandBuffer cmd = GetCommandBuffer(); @@ -1416,6 +1561,31 @@ void main() VK_SUBPASS_CONTENTS_INLINE); VkViewport view = {0.0f, 0.0f, 10.0f, 10.0f, 0.0f, 1.0f}; + + { + VkRect2D scissor = { + {(int32_t)view.x + 1, (int32_t)view.y + 1}, + {(uint32_t)view.width - 2, (uint32_t)view.height - 2}, + }; + vkCmdSetViewport(cmd, 0, 1, &view); + vkCmdSetScissor(cmd, 0, 1, &scissor); + } + + // dummy draw for each slice test texture + pushMarker(cmd, "slice tests"); + setMarker(cmd, "2D array"); + vkCmdBindPipeline(cmd, VK_PIPELINE_BIND_POINT_GRAPHICS, GetPSO(slice_test_array)); + vkh::cmdBindDescriptorSets(cmd, VK_PIPELINE_BIND_POINT_GRAPHICS, layout, 0, + {slice_test_array.set}, {}); + vkCmdDraw(cmd, 0, 0, 0, 0); + + setMarker(cmd, "3D"); + vkCmdBindPipeline(cmd, VK_PIPELINE_BIND_POINT_GRAPHICS, GetPSO(slice_test_3d)); + vkh::cmdBindDescriptorSets(cmd, VK_PIPELINE_BIND_POINT_GRAPHICS, layout, 0, + {slice_test_3d.set}, {}); + vkCmdDraw(cmd, 0, 0, 0, 0); + popMarker(cmd); + for(size_t i = 0; i < test_textures.size(); i++) { if(i == 0 || test_textures[i].fmt.texFmt != test_textures[i - 1].fmt.texFmt || @@ -1464,7 +1634,8 @@ void main() vkCmdEndRenderPass(cmd); - blitToSwap(cmd, fltTex.image, VK_IMAGE_LAYOUT_GENERAL, swapimg, VK_IMAGE_LAYOUT_GENERAL); + blitToSwap(cmd, fltTex.image, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, swapimg, + VK_IMAGE_LAYOUT_GENERAL); FinishUsingBackbuffer(cmd, VK_ACCESS_TRANSFER_WRITE_BIT, VK_IMAGE_LAYOUT_GENERAL); diff --git a/util/test/rdtest/shared/Texture_Zoo.py b/util/test/rdtest/shared/Texture_Zoo.py index d85397528..14770484f 100644 --- a/util/test/rdtest/shared/Texture_Zoo.py +++ b/util/test/rdtest/shared/Texture_Zoo.py @@ -27,8 +27,8 @@ class Texture_Zoo(): self.textures = {} self.filename = '' self.textures = {} - self.controller: rd.ReplayController self.controller = None + self.controller: rd.ReplayController self.out: rd.ReplayOutput self.out = None self.pipeType = rd.GraphicsAPI.D3D11 @@ -479,6 +479,7 @@ class Texture_Zoo(): return picked def check_capture_with_controller(self, proxy_api: str): + self.controller: rd.ReplayController any_failed = False if proxy_api != '': @@ -488,10 +489,68 @@ class Texture_Zoo(): rdtest.log.print('Running on direct replay') self.proxied = False - self.out: rd.ReplayOutput = self.controller.CreateOutput(rd.CreateHeadlessWindowingData(100, 100), rd.ReplayOutputType.Texture) + self.out: rd.ReplayOutput = self.controller.CreateOutput(rd.CreateHeadlessWindowingData(100, 100), + rd.ReplayOutputType.Texture) for d in self.controller.GetDrawcalls(): + if 'slice tests' in d.name: + for sub in d.children: + if 'Draw' in sub.name: + self.controller.SetFrameEvent(sub.eventId, True) + + pipe = self.controller.GetPipelineState() + + tex_id = pipe.GetReadOnlyResources(rd.ShaderStage.Pixel)[0].resources[0].resourceId + + for mip in [0, 1]: + for sl in [16, 17, 18]: + expected = [0.0, 0.0, 1.0, 1.0] + if sl == 17: + expected = [0.0, 1.0, 0.0, 1.0] + + cur_sub = rd.Subresource(mip, sl) + comp_type = rd.CompType.Typeless + + # test that pixel picking sees the right things + picked = self.controller.PickPixel(tex_id, 15, 15, cur_sub, comp_type) + + if not rdtest.value_compare(picked.floatValue, expected): + raise rdtest.TestFailureException( + "Expected to pick {} at slice {} mip {}, got {}" + .format(expected, sl, mip, picked.floatValue)) + + rdtest.log.success('Picked pixel is correct at slice {} mip {}'.format(sl, mip)) + + # Render output texture a three scales - below 100%, 100%, above 100% + tex_display = rd.TextureDisplay() + tex_display.resourceId = tex_id + tex_display.subresource = cur_sub + tex_display.typeCast = comp_type + + # convert the unorm values to byte values for comparison + expected = [int(a * 255) for a in expected[0:3]] + + for scale in [0.9, 1.0, 1.1]: + tex_display.scale = scale + self.out.SetTextureDisplay(tex_display) + self.out.Display() + pixels: bytes = self.out.ReadbackOutputTexture() + + actual = [int(a) for a in pixels[0:3]] + + if not rdtest.value_compare(actual, expected): + raise rdtest.TestFailureException( + "Expected to display {} at slice {} mip {} scale {}%, got {}" + .format(expected, sl, mip, int(scale * 100), actual)) + + rdtest.log.success('Displayed pixel is correct at scale {}% in slice {} mip {}' + .format(int(scale * 100), sl, mip)) + else: + rdtest.log.print('Checking {} for slice display'.format(sub.name)) + + continue + # Check each region for the tests within if d.flags & rd.DrawFlags.PushMarker: name = ''