mirror of
https://github.com/RetroPortingToolKit/psxrecomp
synced 2026-10-25 18:05:12 -04:00
vulkan: order back-to-back color passes
Add same-layout color attachment barriers before geometry and wide-surface render passes so prior writes are visible to LOAD and blend operations. Co-authored-by: Martin Penkava <mpenkava1337@gmail.com> Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,22 @@
|
||||
# Martin Penkava PR #16: Vulkan color pass self-barrier
|
||||
|
||||
Last evaluated: 2026-07-14
|
||||
|
||||
| Item | Value |
|
||||
| --- | --- |
|
||||
| Head repository/branch | `shaneomac1337/psxrecomp`, `smackdown2-fixes` (submitted as `mstan/psxrecomp` PR #16) |
|
||||
| Source commit | `4517bd5a3ed0901a2402ff7b93bebe3de2cf9afd` |
|
||||
| Source author | Martin Penkava `<mpenkava1337@gmail.com>` |
|
||||
| Source co-author trailer | Claude Fable 5 `<noreply@anthropic.com>` |
|
||||
| Local base | `7085721afe338a03cb114321a3576cdff420b732` (`origin/master`) |
|
||||
| Local branch | `fix/pr16-vulkan-color-pass-barrier-mpenkava` |
|
||||
|
||||
## Included scope
|
||||
|
||||
Adds an explicit color-attachment memory dependency between back-to-back geometry, wide-surface, and wide-clear render passes when the image remains in `COLOR_ATTACHMENT_OPTIMAL`. This mirrors the existing depth/stencil ordering and covers drivers that do not tolerate the missing external dependency.
|
||||
|
||||
## Deliberate exclusions
|
||||
|
||||
- Packed upload alignment and swapchain acquire synchronization are isolated on separate branches.
|
||||
- All `PSX_VK_*` WIP diagnostics from the source commit are excluded.
|
||||
- CRT shaders and the later presentation redesign are excluded.
|
||||
@@ -1685,6 +1685,29 @@ static void set_scissor_px(VkCommandBuffer cb, int x, int y, int w, int h) {
|
||||
VkRect2D sc = { { x * s_scale, y * s_scale }, { (uint32_t)(w * s_scale), (uint32_t)(h * s_scale) } };
|
||||
p_vkCmdSetScissor(cb, 0, 1, &sc);
|
||||
}
|
||||
|
||||
/* A same-layout transition is elided by img_to(), while the render pass has
|
||||
* no external dependency. Explicitly order a preceding pass's attachment
|
||||
* writes before a following LOAD/blend pass on the same color image. */
|
||||
static void color_self_barrier(VkCommandBuffer cb, VkImage img) {
|
||||
VkImageMemoryBarrier barrier = { VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER };
|
||||
barrier.oldLayout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL;
|
||||
barrier.newLayout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL;
|
||||
barrier.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
|
||||
barrier.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
|
||||
barrier.image = img;
|
||||
barrier.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
|
||||
barrier.subresourceRange.levelCount = 1;
|
||||
barrier.subresourceRange.layerCount = 1;
|
||||
barrier.srcAccessMask = VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT;
|
||||
barrier.dstAccessMask = VK_ACCESS_COLOR_ATTACHMENT_READ_BIT |
|
||||
VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT;
|
||||
p_vkCmdPipelineBarrier(cb,
|
||||
VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT,
|
||||
VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT,
|
||||
0, 0, NULL, 0, NULL, 1, &barrier);
|
||||
}
|
||||
|
||||
static void begin_geo_pass(VkCommandBuffer cb) {
|
||||
/* Explicit stencil ordering across one-shot submits: this pass both TESTS
|
||||
* and WRITES the stencil (PSX mask bits) that a PRIOR submit's pass wrote.
|
||||
@@ -1709,6 +1732,7 @@ static void begin_geo_pass(VkCommandBuffer cb) {
|
||||
VK_PIPELINE_STAGE_LATE_FRAGMENT_TESTS_BIT,
|
||||
VK_PIPELINE_STAGE_EARLY_FRAGMENT_TESTS_BIT | VK_PIPELINE_STAGE_LATE_FRAGMENT_TESTS_BIT,
|
||||
0, 0, NULL, 0, NULL, 1, &db);
|
||||
color_self_barrier(cb, s_vram_img);
|
||||
VkRenderPassBeginInfo rp = { VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO };
|
||||
rp.renderPass = s_rpass; rp.framebuffer = s_fbo;
|
||||
rp.renderArea.extent.width = VRAM_W * s_scale;
|
||||
@@ -2235,6 +2259,7 @@ static void wide_pass_begin(VkCommandBuffer cb) {
|
||||
VK_PIPELINE_STAGE_LATE_FRAGMENT_TESTS_BIT,
|
||||
VK_PIPELINE_STAGE_EARLY_FRAGMENT_TESTS_BIT | VK_PIPELINE_STAGE_LATE_FRAGMENT_TESTS_BIT,
|
||||
0, 0, NULL, 0, NULL, 1, &db);
|
||||
color_self_barrier(cb, s_wide_img[i]);
|
||||
VkRenderPassBeginInfo rp = { VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO };
|
||||
rp.renderPass = s_rpass; rp.framebuffer = s_wide_fb[i];
|
||||
rp.renderArea.extent.width = (uint32_t)(s_wide_w * S);
|
||||
@@ -2728,6 +2753,7 @@ static void vkb_wide_clear(int base_x, int y, int h, uint16_t color) {
|
||||
if (y1 <= y0) return;
|
||||
VkCommandBuffer cb = begin_oneshot();
|
||||
img_to(cb, s_wide_img[i], &s_wide_layout[i], VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL);
|
||||
color_self_barrier(cb, s_wide_img[i]);
|
||||
VkRenderPassBeginInfo rp = { VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO };
|
||||
rp.renderPass = s_rpass; rp.framebuffer = s_wide_fb[i];
|
||||
rp.renderArea.extent.width = (uint32_t)(s_wide_w * S);
|
||||
@@ -2765,6 +2791,7 @@ static void vkb_wide_clear_margins(int base_x, int y, int h, uint16_t color, int
|
||||
if (y1 <= y0 || margin * 2 >= W) return;
|
||||
VkCommandBuffer cb = begin_oneshot();
|
||||
img_to(cb, s_wide_img[i], &s_wide_layout[i], VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL);
|
||||
color_self_barrier(cb, s_wide_img[i]);
|
||||
VkRenderPassBeginInfo rp = { VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO };
|
||||
rp.renderPass = s_rpass; rp.framebuffer = s_wide_fb[i];
|
||||
rp.renderArea.extent.width = (uint32_t)W;
|
||||
|
||||
@@ -0,0 +1,21 @@
|
||||
#!/usr/bin/env python3
|
||||
from pathlib import Path
|
||||
import re
|
||||
|
||||
source = (Path(__file__).parents[1] / "src" / "gpu_vk_renderer.c").read_text()
|
||||
helper = re.search(
|
||||
r"static void color_self_barrier\(.*?\n\}", source, flags=re.DOTALL
|
||||
)
|
||||
assert helper, "color_self_barrier not found"
|
||||
body = helper.group(0)
|
||||
for token in (
|
||||
"VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL",
|
||||
"VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT",
|
||||
"VK_ACCESS_COLOR_ATTACHMENT_READ_BIT",
|
||||
"VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT",
|
||||
):
|
||||
assert token in body, f"missing {token}"
|
||||
|
||||
assert source.count("color_self_barrier(cb, s_vram_img)") == 1
|
||||
assert source.count("color_self_barrier(cb, s_wide_img[i])") == 3
|
||||
print("Vulkan color self-barrier test passed")
|
||||
Reference in New Issue
Block a user