mirror of
https://github.com/baldurk/renderdoc.git
synced 2026-08-28 01:16:31 +00:00
VK_Indirect test improvements
Check ALL overlays on ALL EIDs don't crash Add some IndirectCount draws to VK_Indirect for testing overlays Check overlays produce output and pixel history is not empty for each non-empty draw Check overlays produce expected output for empty draws i.e. empty except for *Pass overlay modes Check Quad Overdraw and Triangle Size overlays outputs match when comparing the Pass and Draw versions
This commit is contained in:
@@ -81,8 +81,8 @@ void main()
|
||||
ssbo.data[6].x = 15;
|
||||
|
||||
// write count parameters for indirect count draws, although we might not need these
|
||||
// 1 draw for non-indexed, 3 draws for indexed.
|
||||
ssbo.data[10] = uvec4(1, 3, 0, 0);
|
||||
// 1 draw non-indexed, 3 indexed, 3 non-indexed, 0 indexed
|
||||
ssbo.data[10] = uvec4(1, 3, 3, 0);
|
||||
|
||||
// vkCmdDrawIndirectCountKHR()
|
||||
ssbo.data[11] = uvec4(3, 4, 3, 4); // draw verts 3..5
|
||||
@@ -94,6 +94,11 @@ void main()
|
||||
ssbo.data[15].x = 200;
|
||||
ssbo.data[16] = uvec4(6, 2, 12, 0); // draw indices 12..17
|
||||
ssbo.data[17].x = 1;
|
||||
|
||||
// vkCmdDrawIndirectCountKHR()
|
||||
ssbo.data[20] = uvec4(3, 4, 3, 4); // draw verts 3..5
|
||||
ssbo.data[21] = uvec4(3, 2, 6, 2); // draw verts 6..8
|
||||
ssbo.data[22] = uvec4(3, 5, 9, 5); // draw verts 9..11
|
||||
}
|
||||
}
|
||||
|
||||
@@ -362,9 +367,23 @@ void main()
|
||||
// if we have KHR_draw_indirect_count, test it as well
|
||||
if(KHR_draw_indirect_count)
|
||||
{
|
||||
pushMarker(cmd, "Primary: KHR_draw_indirect_count");
|
||||
pushMarker(cmd, "Primary: Indirect count draws Three & Three");
|
||||
VkViewport viewport = mainWindow->viewport;
|
||||
viewport.x += viewport.width / 2.0f;
|
||||
viewport.y += viewport.height / 2.0f;
|
||||
viewport.width *= 0.5f;
|
||||
viewport.height *= 0.5f;
|
||||
vkCmdSetViewport(cmd, 0, 1, &viewport);
|
||||
vkCmdDrawIndirectCountKHR(cmd, ssbo.buffer, 20 * sizeof(uvec4), ssbo.buffer,
|
||||
10 * sizeof(uvec4) + 2 * sizeof(uint32_t), 10, sizeof(uvec4));
|
||||
vkCmdDrawIndexedIndirectCountKHR(cmd, ssbo.buffer, 12 * sizeof(uvec4), ssbo.buffer,
|
||||
10 * sizeof(uvec4) + sizeof(uint32_t), 10,
|
||||
sizeof(uvec4) * 2);
|
||||
popMarker(cmd);
|
||||
|
||||
pushMarker(cmd, "Primary: KHR_action_indirect_count");
|
||||
pushMarker(cmd, "Primary: Empty count draws");
|
||||
vkCmdSetViewport(cmd, 0, 1, &mainWindow->viewport);
|
||||
// empty draws
|
||||
vkCmdDrawIndirectCountKHR(cmd, ssbo.buffer, 11 * sizeof(uvec4), ssbo.buffer,
|
||||
10 * sizeof(uvec4), 0, sizeof(uvec4));
|
||||
@@ -372,7 +391,7 @@ void main()
|
||||
10 * sizeof(uvec4) + sizeof(uint32_t), 0,
|
||||
sizeof(uvec4) * 2);
|
||||
vkCmdDrawIndexedIndirectCountKHR(cmd, ssbo.buffer, 12 * sizeof(uvec4), ssbo.buffer,
|
||||
10 * sizeof(uvec4) + sizeof(uint32_t) * 2, 10,
|
||||
10 * sizeof(uvec4) + sizeof(uint32_t) * 3, 10,
|
||||
sizeof(uvec4) * 2);
|
||||
popMarker(cmd);
|
||||
|
||||
@@ -562,7 +581,7 @@ void main()
|
||||
10 * sizeof(uvec4) + sizeof(uint32_t), 0,
|
||||
sizeof(uvec4) * 2);
|
||||
vkCmdDrawIndexedIndirectCountKHR(cmd, ssbo.buffer, 12 * sizeof(uvec4), ssbo.buffer,
|
||||
10 * sizeof(uvec4) + sizeof(uint32_t) * 2, 10,
|
||||
10 * sizeof(uvec4) + sizeof(uint32_t) * 3, 10,
|
||||
sizeof(uvec4) * 2);
|
||||
popMarker(cmd);
|
||||
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import rdtest
|
||||
import struct
|
||||
import renderdoc as rd
|
||||
|
||||
from typing import List
|
||||
|
||||
def real_action_children(action):
|
||||
return [c for c in action.children if not c.flags & rd.ActionFlags.PopMarker]
|
||||
@@ -10,6 +10,66 @@ def real_action_children(action):
|
||||
class VK_Indirect(rdtest.TestCase):
|
||||
demos_test_name = 'VK_Indirect'
|
||||
|
||||
samples = [
|
||||
(50, 40),
|
||||
(60, 40),
|
||||
(70, 40),
|
||||
|
||||
(90, 40),
|
||||
(100, 40),
|
||||
(110, 40),
|
||||
|
||||
(130, 40),
|
||||
(140, 40),
|
||||
(160, 40),
|
||||
|
||||
(190, 40),
|
||||
(200, 40),
|
||||
(220, 40),
|
||||
|
||||
|
||||
|
||||
(50, 190),
|
||||
(60, 190),
|
||||
(70, 190),
|
||||
|
||||
(90, 190),
|
||||
(100, 190),
|
||||
(110, 190),
|
||||
|
||||
(130, 190),
|
||||
(140, 190),
|
||||
(160, 190),
|
||||
|
||||
(190, 190),
|
||||
(200, 190),
|
||||
(220, 190),
|
||||
|
||||
|
||||
|
||||
(330, 40),
|
||||
(340, 40),
|
||||
(350, 40),
|
||||
|
||||
(330, 115),
|
||||
(340, 115),
|
||||
(350, 115),
|
||||
|
||||
(330, 190),
|
||||
(340, 190),
|
||||
(350, 190),
|
||||
]
|
||||
|
||||
def check_pixel_history_succeeds(self, eid: int, x: int, y: int):
|
||||
pipe: rd.PipeState = self.controller.GetPipelineState()
|
||||
rt = pipe.GetOutputTargets()[0]
|
||||
tex = rt.resource
|
||||
sub = rd.Subresource()
|
||||
modifs: List[rd.PixelModification] = self.controller.PixelHistory(tex, x, y, sub, rt.format.compType)
|
||||
if len(modifs) < 2:
|
||||
raise rdtest.TestFailureException(f"EID: {eid} No pixel history found at ({x}, {y})")
|
||||
rdtest.log.success(f"EID: {eid} Pixel History {x}, {y} Worked")
|
||||
|
||||
def check_overlay(self, pass_samples, *, no_overlay = False):
|
||||
pipe: rd.PipeState = self.controller.GetPipelineState()
|
||||
|
||||
@@ -23,70 +83,238 @@ class VK_Indirect(rdtest.TestCase):
|
||||
|
||||
overlay_id = self.out.GetDebugOverlayTexID()
|
||||
|
||||
samples = [
|
||||
(50, 40),
|
||||
(60, 40),
|
||||
(70, 40),
|
||||
|
||||
(90, 40),
|
||||
(100, 40),
|
||||
(110, 40),
|
||||
|
||||
(130, 40),
|
||||
(140, 40),
|
||||
(160, 40),
|
||||
|
||||
(190, 40),
|
||||
(200, 40),
|
||||
(220, 40),
|
||||
|
||||
|
||||
|
||||
(50, 190),
|
||||
(60, 190),
|
||||
(70, 190),
|
||||
|
||||
(90, 190),
|
||||
(100, 190),
|
||||
(110, 190),
|
||||
|
||||
(130, 190),
|
||||
(140, 190),
|
||||
(160, 190),
|
||||
|
||||
(190, 190),
|
||||
(200, 190),
|
||||
(220, 190),
|
||||
|
||||
|
||||
|
||||
(330, 40),
|
||||
(340, 40),
|
||||
(350, 40),
|
||||
|
||||
(330, 115),
|
||||
(340, 115),
|
||||
(350, 115),
|
||||
|
||||
(330, 190),
|
||||
(340, 190),
|
||||
(350, 190),
|
||||
]
|
||||
|
||||
# Every sample that isn't passing should be off
|
||||
off_alpha = 0.5
|
||||
# If the overlay isn't even for a action, it will be cleared to black
|
||||
if no_overlay:
|
||||
off_alpha = 0.0
|
||||
self.check(len(pass_samples) == 0)
|
||||
for s in [s for s in samples if s not in pass_samples]:
|
||||
for s in [s for s in self.samples if s not in pass_samples]:
|
||||
self.check_pixel_value(overlay_id, s[0], s[1], [0.0, 0.0, 0.0, off_alpha], eps=1.0/256.0)
|
||||
|
||||
# And the passing samples should be on
|
||||
for s in pass_samples:
|
||||
self.check_pixel_value(overlay_id, s[0], s[1], [0.8, 0.1, 0.8, 1.0], eps=1.0/256.0)
|
||||
|
||||
def get_overlay_pixel(self, overlay: rd.DebugOverlay, col_tex: rd.ResourceId, x: int, y: int):
|
||||
tex = rd.TextureDisplay()
|
||||
tex.resourceId = col_tex
|
||||
tex.overlay = overlay
|
||||
tex.subresource.sample = 0
|
||||
|
||||
out: rd.ReplayOutput = self.controller.CreateOutput(rd.CreateHeadlessWindowingData(100, 100), rd.ReplayOutputType.Texture)
|
||||
out.SetTextureDisplay(tex)
|
||||
out.Display()
|
||||
overlayTex: rd.ResourceId = out.GetDebugOverlayTexID()
|
||||
if overlay == rd.DebugOverlay.ClearBeforeDraw:
|
||||
overlayTex = col_tex
|
||||
if overlay == rd.DebugOverlay.ClearBeforePass:
|
||||
overlayTex = col_tex
|
||||
|
||||
picked = self.controller.PickPixel(overlayTex, x, y, rd.Subresource(), rd.CompType.UNorm)
|
||||
out.Shutdown()
|
||||
return picked
|
||||
|
||||
def check_overlays(self, eid: int, x: int, y: int):
|
||||
with rdtest.log.auto_section(f'EID {eid} Checking Overlays at {x}, {y}'):
|
||||
pipe: rd.PipeState = self.controller.GetPipelineState()
|
||||
if len(pipe.GetOutputTargets()) == 0:
|
||||
raise rdtest.TestFailureException("No output targets found")
|
||||
|
||||
col_tex: rd.ResourceId = pipe.GetOutputTargets()[0].resource
|
||||
|
||||
for overlay in rd.DebugOverlay:
|
||||
if overlay == rd.DebugOverlay.NoOverlay:
|
||||
continue
|
||||
if overlay == rd.DebugOverlay.NaN or overlay == rd.DebugOverlay.Clipping:
|
||||
continue
|
||||
if overlay == rd.DebugOverlay.ViewportScissor:
|
||||
continue
|
||||
|
||||
emptyPixel = (0.0, 0.0, 0.0, 0.0)
|
||||
picked = self.get_overlay_pixel(overlay, col_tex, x, y)
|
||||
if picked.floatValue == emptyPixel:
|
||||
raise rdtest.TestFailureException(f"{overlay.name} overlay is empty")
|
||||
|
||||
# Check "Quad Overdraw (Draw)/(Pass)" match
|
||||
pickedDraw = self.get_overlay_pixel(rd.DebugOverlay.QuadOverdrawDraw, col_tex, x, y)
|
||||
pickedPass = self.get_overlay_pixel(rd.DebugOverlay.QuadOverdrawPass, col_tex, x, y)
|
||||
if pickedDraw.floatValue != pickedPass.floatValue:
|
||||
raise rdtest.TestFailureException(f"Quad Overdraw Draw and Pass do not match: {pickedDraw.floatValue} vs {pickedPass.floatValue}")
|
||||
pickedDraw = self.get_overlay_pixel(rd.DebugOverlay.TriangleSizeDraw, col_tex, x, y)
|
||||
pickedPass = self.get_overlay_pixel(rd.DebugOverlay.TriangleSizePass, col_tex, x, y)
|
||||
if pickedDraw.floatValue != pickedPass.floatValue:
|
||||
raise rdtest.TestFailureException(f"Triangle Size Draw and Pass do not match: {pickedDraw.floatValue} vs {pickedPass.floatValue}")
|
||||
|
||||
def check_overlay_and_pixel_history(self, eid, coords):
|
||||
self.controller.SetFrameEvent(eid, False)
|
||||
for c in coords:
|
||||
x = c[0]
|
||||
y = c[1]
|
||||
self.check_overlays(eid, x, y)
|
||||
self.check_pixel_history_succeeds(eid, x, y)
|
||||
|
||||
def check_overlays_and_pixel_history(self):
|
||||
for level in ["Primary", "Secondary"]:
|
||||
action = self.find_action(f"{level}: Indirect draws")
|
||||
|
||||
# vkCmdDrawIndirect : 1
|
||||
action = self.find_action("vkCmdDrawIndirect", action.eventId)
|
||||
eid = action.eventId
|
||||
coords = [(60, 60)]
|
||||
self.check_overlay_and_pixel_history(eid, coords)
|
||||
|
||||
# vkCmdDrawIndexedIndirect : 2
|
||||
action = self.find_action("vkCmdDrawIndexedIndirect", action.eventId)
|
||||
eid = action.eventId
|
||||
# Draw Action 1
|
||||
eid += 1
|
||||
coords = [(100, 60)]
|
||||
self.check_overlay_and_pixel_history(eid, coords)
|
||||
# Draw Action 2
|
||||
eid += 1
|
||||
coords = [(140, 40), (200, 40)]
|
||||
self.check_overlay_and_pixel_history(eid, coords)
|
||||
|
||||
action = self.find_action(f"{level}: Indirect count draws Three & Three")
|
||||
if action:
|
||||
# vkCmdDrawIndirectCount : 3
|
||||
action = self.find_action("vkCmdDrawIndirectCount", action.eventId)
|
||||
eid = action.eventId
|
||||
# Draw Action 1
|
||||
eid += 1
|
||||
coords = [(230, 250)]
|
||||
self.check_overlay_and_pixel_history(eid, coords)
|
||||
# Draw Action 2
|
||||
eid += 1
|
||||
coords = [(250, 180)]
|
||||
self.check_overlay_and_pixel_history(eid, coords)
|
||||
# Draw Action 3
|
||||
eid += 1
|
||||
coords = [(270, 170)]
|
||||
self.check_overlay_and_pixel_history(eid, coords)
|
||||
|
||||
# vkCmdDrawIndexedIndirectCount : 3
|
||||
action = self.find_action("vkCmdDrawIndexedIndirectCount", action.eventId)
|
||||
eid = action.eventId
|
||||
# Draw Action 1
|
||||
eid += 1
|
||||
coords = [(250, 250)]
|
||||
self.check_overlay_and_pixel_history(eid, coords)
|
||||
# Draw Action 2 : no draw
|
||||
eid += 1
|
||||
# Draw Action 3
|
||||
eid += 1
|
||||
coords = [(270, 245),(300,245)]
|
||||
self.check_overlay_and_pixel_history(eid, coords)
|
||||
|
||||
action = self.find_action(f"{level}: KHR_action_indirect_count")
|
||||
if action:
|
||||
# Primary: Indirect count draws
|
||||
action = self.find_action(f"{level}: Indirect count draws", action.eventId)
|
||||
# vkCmdDrawIndirectCount : 1
|
||||
action = self.find_action("vkCmdDrawIndirectCount", action.eventId)
|
||||
eid = action.eventId
|
||||
# Draw Action 1
|
||||
eid += 1
|
||||
coords = [(60, 200)]
|
||||
self.check_overlay_and_pixel_history(eid, coords)
|
||||
# vkCmdDrawIndexedIndirectCount : 3
|
||||
action = self.find_action("vkCmdDrawIndexedIndirectCount", action.eventId)
|
||||
eid = action.eventId
|
||||
# Draw Action 1
|
||||
eid += 1
|
||||
coords = [(100, 200)]
|
||||
self.check_overlay_and_pixel_history(eid, coords)
|
||||
# Draw Action 2 : no draw
|
||||
eid += 1
|
||||
# Draw Action 3
|
||||
eid += 1
|
||||
coords = [(140, 190),(200,190)]
|
||||
self.check_overlay_and_pixel_history(eid, coords)
|
||||
|
||||
# Primary : Post-count 1
|
||||
action = self.find_action(f"{level}: Post-count 1")
|
||||
# vkCmdDraw : 1
|
||||
action = self.find_action("vkCmdDraw", action.eventId)
|
||||
eid = action.eventId
|
||||
coords = [(340, 60)]
|
||||
self.check_overlay_and_pixel_history(eid, coords)
|
||||
|
||||
# Primary : Post-count 2
|
||||
action = self.find_action(f"{level}: Post-count 2")
|
||||
# vkCmdDraw : 1
|
||||
action = self.find_action("vkCmdDraw", action.eventId)
|
||||
eid = action.eventId
|
||||
coords = [(340, 200)]
|
||||
self.check_overlay_and_pixel_history(eid, coords)
|
||||
|
||||
# Primary : Post-count 3
|
||||
action = self.find_action(f"{level}: Post-count 3")
|
||||
# vkCmdDraw : 1
|
||||
action = self.find_action("vkCmdDraw", action.eventId)
|
||||
eid = action.eventId
|
||||
coords = [(340, 140)]
|
||||
self.check_overlay_and_pixel_history(eid, coords)
|
||||
|
||||
def check_empty_draw_overlays(self):
|
||||
with rdtest.log.auto_section('Checking Empty Draws'):
|
||||
for level in ["Primary", "Secondary"]:
|
||||
empties = self.find_action(f"{level}: Empty count draws")
|
||||
action: rd.ActionDescription
|
||||
for action in real_action_children(empties):
|
||||
eid = action.eventId
|
||||
self.controller.SetFrameEvent(eid, False)
|
||||
pipe = self.controller.GetPipelineState()
|
||||
for overlay in rd.DebugOverlay:
|
||||
if overlay == rd.DebugOverlay.NoOverlay:
|
||||
continue
|
||||
if overlay == rd.DebugOverlay.NaN or overlay == rd.DebugOverlay.Clipping:
|
||||
continue
|
||||
if overlay == rd.DebugOverlay.ViewportScissor:
|
||||
continue
|
||||
if overlay == rd.DebugOverlay.Wireframe:
|
||||
continue
|
||||
tex = rd.TextureDisplay()
|
||||
col_tex: rd.ResourceId = pipe.GetOutputTargets()[0].resource
|
||||
tex.resourceId = col_tex
|
||||
tex.overlay = overlay
|
||||
tex.subresource.sample = 0
|
||||
out: rd.ReplayOutput = self.controller.CreateOutput(rd.CreateHeadlessWindowingData(100, 100), rd.ReplayOutputType.Texture)
|
||||
out.SetTextureDisplay(tex)
|
||||
out.Display()
|
||||
overlayTex: rd.ResourceId = out.GetDebugOverlayTexID()
|
||||
expectEmpty = True
|
||||
if overlay == rd.DebugOverlay.ClearBeforeDraw:
|
||||
overlayTex = col_tex
|
||||
if overlay == rd.DebugOverlay.ClearBeforePass:
|
||||
overlayTex = col_tex
|
||||
if overlay == rd.DebugOverlay.ClearBeforePass:
|
||||
expectEmpty = False
|
||||
if overlay == rd.DebugOverlay.QuadOverdrawPass:
|
||||
expectEmpty = False
|
||||
if overlay == rd.DebugOverlay.TriangleSizePass:
|
||||
expectEmpty = False
|
||||
|
||||
empty = True
|
||||
emptyPixel = (0.0, 0.0, 0.0, 0.0)
|
||||
if overlay == rd.DebugOverlay.Drawcall:
|
||||
emptyPixel = (0.0, 0.0, 0.0, 0.5)
|
||||
|
||||
for s in self.samples:
|
||||
x = s[0]
|
||||
y = s[1]
|
||||
picked = self.controller.PickPixel(overlayTex, x, y, rd.Subresource(), rd.CompType.Float)
|
||||
if picked.floatValue != emptyPixel:
|
||||
empty = False
|
||||
if expectEmpty and not empty:
|
||||
raise rdtest.TestFailureException(f"EID {eid} {overlay.name} {x}, {y} {picked.floatValue} is not as expected {emptyPixel}")
|
||||
if expectEmpty != empty:
|
||||
raise rdtest.TestFailureException(f"EID {eid} {overlay.name} is not as expected")
|
||||
|
||||
out.Shutdown()
|
||||
|
||||
def check_capture(self):
|
||||
|
||||
fill = self.find_action("vkCmdFillBuffer")
|
||||
|
||||
self.check(fill is not None)
|
||||
@@ -286,6 +514,7 @@ class VK_Indirect(rdtest.TestCase):
|
||||
rdtest.log.success("{} {} is as expected".format(level, action.customName))
|
||||
|
||||
if indirect_count_root is not None:
|
||||
rdtest.log.print(f"{indirect_count_root.children[1].customName}")
|
||||
self.check(indirect_count_root.children[0].customName == '{}: Empty count draws'.format(level))
|
||||
self.check(indirect_count_root.children[1].customName == '{}: Indirect count draws'.format(level))
|
||||
|
||||
@@ -294,7 +523,7 @@ class VK_Indirect(rdtest.TestCase):
|
||||
self.check(empties and len(real_action_children(empties)) == 3)
|
||||
|
||||
action: rd.ActionDescription
|
||||
for action in real_action_children(empties.children):
|
||||
for action in real_action_children(empties):
|
||||
self.check(action.numIndices == 0)
|
||||
self.check(action.numInstances == 0)
|
||||
|
||||
@@ -422,3 +651,27 @@ class VK_Indirect(rdtest.TestCase):
|
||||
self.check_overlay([(340, 115)])
|
||||
else:
|
||||
rdtest.log.print("KHR_action_indirect_count not tested")
|
||||
|
||||
with rdtest.log.auto_section('Checking Overlays And Pixel History'):
|
||||
self.check_overlays_and_pixel_history()
|
||||
|
||||
with rdtest.log.auto_section('Checking All Overlays'):
|
||||
for eid in range(self.get_first_action().eventId, self.get_last_action().eventId + 1):
|
||||
self.controller.SetFrameEvent(eid, False)
|
||||
pipe = self.controller.GetPipelineState()
|
||||
if len(pipe.GetOutputTargets()) == 0:
|
||||
continue
|
||||
rdtest.log.print(f"EID: {eid}")
|
||||
for overlay in rd.DebugOverlay:
|
||||
tex = rd.TextureDisplay()
|
||||
col_tex: rd.ResourceId = pipe.GetOutputTargets()[0].resource
|
||||
tex.resourceId = col_tex
|
||||
tex.overlay = overlay
|
||||
tex.subresource.sample = 0
|
||||
|
||||
out: rd.ReplayOutput = self.controller.CreateOutput(rd.CreateHeadlessWindowingData(100, 100), rd.ReplayOutputType.Texture)
|
||||
out.SetTextureDisplay(tex)
|
||||
out.Display()
|
||||
out.Shutdown()
|
||||
|
||||
self.check_empty_draw_overlays()
|
||||
Reference in New Issue
Block a user