Fix display of 3D texture slices when linear sampling

* When displaying mip 0 of a texture at less than 100% zoom we linear sampling,
  but we don't want to linear sample across slices. Adding a half pixel offset
  in z ensures we sample precisely on the slice itself.
This commit is contained in:
baldurk
2021-01-20 16:16:28 +00:00
parent 309a08373b
commit 20d8ae2dcf
13 changed files with 541 additions and 50 deletions
+3 -3
View File
@@ -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)
{
+3 -3
View File
@@ -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)
{
+3 -3
View File
@@ -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)
{
+4 -5
View File
@@ -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)
{
+12 -2
View File
@@ -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)
{
+17 -5
View File
@@ -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<D3D12_RESOURCE_BARRIER> 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))
+27 -19
View File
@@ -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 = {};
+11 -2
View File
@@ -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));
@@ -1026,6 +1026,46 @@ int4 main(float4 pos : SV_Position, uint samp : SV_SampleIndex) : SV_Target0
ds.StencilEnable = FALSE;
SetDepthState(ds);
std::vector<Vec4f> blue;
blue.resize(64 * 64 * 64, Vec4f(0.0f, 0.0f, 1.0f, 1.0f));
std::vector<Vec4f> 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 ||
+127 -1
View File
@@ -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<Vec4f> blue;
blue.resize(64 * 64 * 64, Vec4f(0.0f, 0.0f, 1.0f, 1.0f));
std::vector<Vec4f> 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 ||
+42
View File
@@ -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<Vec4f> blue;
blue.resize(64 * 64 * 64, Vec4f(0.0f, 0.0f, 1.0f, 1.0f));
std::vector<Vec4f> 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)
+176 -5
View File
@@ -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<Vec4f> blue;
blue.resize(64 * 64 * 64, Vec4f(0.0f, 0.0f, 1.0f, 1.0f));
std::vector<Vec4f> 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);
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);
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);
copy.imageExtent.depth = 32;
copy.imageSubresource.layerCount = 1;
vkCmdCopyBufferToImage(cmd, uploadBuf.buffer, slice_test_3d.res.image,
VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, 1, &copy);
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);
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);
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);
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);
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);
+61 -2
View File
@@ -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 = ''