mirror of
https://github.com/libretro/RetroArch.git
synced 2026-11-08 08:10:30 -10:00
vulkan, d3d12: a frame pushed as a window into the driver's own loan is read out of the loan
A core that renders into the buffer GET_CURRENT_SOFTWARE_FRAMEBUFFER
lends it may push back a pointer partway into that buffer, at the
buffer's pitch, with the size of the window it wants shown: that is
how an overscan crop is done by offset, and beetle-psx does exactly
that since 3f5be07 - the whole 700x480 scanout surface is rendered
into the loan and the visible part pushed. The threaded wrapper has
accepted such a push as a lend since 9ed0db58c3. The drivers' own
loans, the ones handed out with threaded video off, did not.
The Vulkan driver knew a lent frame only by the exact pointer of its
swapchain-index texture's mapping, so a window into it was a frame
of another size than the texture: the texture was recreated at the
window's size every frame (and again at the loan's size at the next
lend), the loan went to the deferred list, and the window was copied
out of the parked mapping by the host. That worked while the core
kept pushing. The cached frame kept naming the parked mapping,
though, and when the core stopped - the menu opened over a paused
core, or the window lost focus with pause-on-focus-loss on - every
iteration redrew the cached frame; after the deferral window the
mapping was unmapped and freed, and the next redraw read it. That is
libretro/RetroArch#19652 (Beetle PSX on an RTX 4060: memcpy fault
from vulkan_frame's row copy on entering core options or on losing
focus).
vulkan_frame() now tests a pushed frame against the texture's mapping
(vulkan_frame_window): inside it, on its pitch, whole, word-aligned.
Such a window leaves the texture alone - it keeps the loan's size for
the next lend and its mapping stays mapped, which is what the cached
frame needs - and is cut out on the GPU into texture_optimal, which
is what gets sampled: vkCmdCopyImage with a source offset for a
streamed linear image (the XRGB8888 case), vkCmdCopyBufferToImage
with a buffer offset and row length for a staging buffer, and a word
offset in the RGB565 compute upload's UBO (rgb565_to_rgba8888.comp,
.inc regenerated). No host copy, no texture per frame. texture_optimal
is kept at the frame's size whenever it exists, since it is sampled
whenever it exists; a window-sized one left over from a window is
recreated for a staging texture and retired for a streamed one. A
frame inside the mapping that is not a window (another pitch) is
still copied out, and the cached frame is then retired, so a paused
redraw can never follow a parked mapping again.
The D3D12 driver's loan is a persistent buffer of its own, so it was
memory-safe, but it decided by a flag set when the loan was asked
for, not by what was pushed: a window pushed into it was copied as
the whole footprint into a window-sized texture, and a core that
asked and then pushed its own buffer, or a dupe, was shown the loan.
It now makes the same pointer test (d3d12_sw_fb_window) and copies
the window's box out of the loan's footprint; the flag is gone.
Three GFX_INSTRUMENT counters cover the path: frame textures
created, frames copied by the host, frames read out of a loan.
The threaded-video harness gets a lane for it: threaded video off on
the real driver, the harness core's cropped-window lend for 60
frames, then the menu opened over the paused core for longer than
any deferral window. On the old driver on lavapipe under ASan the
lane counts 59 grants and 0 frames read out of the loan, then the
paused redraw aborts with the use-after-free; on the new one 39 of
40 pushes are read out of the loan (the 41st is the core's own
oversize frame, copied as it should be), no host copy, 3 frame
textures over 60 frames, and the paused redraw runs through with
the validation layer silent. It runs on the release, ASan and TSan
legs of Linux-vulkan-validation.yml as they are.
This commit is contained in:
1 parent
8261ec0550
commit
7510039d5d
7 files changed
+558
-207
No files matched your search
+85
-32
@@ -58,6 +58,7 @@
|
||||
#include "../../configuration.h"
|
||||
#include "../../retroarch.h"
|
||||
#include "../font_driver.h"
|
||||
#include "../gfx_instrument.h"
|
||||
#include "../common/win32_common.h"
|
||||
#include "../../performance_counters.h"
|
||||
#include "../../menu/menu_driver.h"
|
||||
@@ -117,7 +118,6 @@ enum d3d12_video_flags
|
||||
D3D12_ST_FLAG_WAITABLE_SWAPCHAINS = (1 << 13),
|
||||
D3D12_ST_FLAG_HW_IFACE_ENABLE = (1 << 14),
|
||||
D3D12_ST_FLAG_FRAME_DUPE_LOCK = (1 << 15),
|
||||
D3D12_ST_FLAG_SW_FRAMEBUFFER_READY = (1 << 16),
|
||||
/* The core's frames are already PQ-encoded Rec.2020 at absolute
|
||||
* luminance (RETRO_PIXEL_FORMAT_HDR10_2101010), so the HDR composition
|
||||
* must pass them through rather than encode them a second time. */
|
||||
@@ -1062,8 +1062,15 @@ static void d3d12_init_texture(D3D12Device device, d3d12_texture_t* texture)
|
||||
texture->size_data.w = 1.0f / texture->desc.Height;
|
||||
}
|
||||
|
||||
static void d3d12_upload_texture(D3D12GraphicsCommandList cmd,
|
||||
d3d12_texture_t* texture, void *userdata)
|
||||
/* Copy @texture's pixels in from @upload_buffer laid out as @layout:
|
||||
* the texture's own upload buffer, or the driver's lent framebuffer.
|
||||
* @src_box, when given, is the part of that footprint to copy - a
|
||||
* window into a loan - and the texture is its size. */
|
||||
static void d3d12_upload_texture_from(D3D12GraphicsCommandList cmd,
|
||||
d3d12_texture_t* texture, void *userdata,
|
||||
D3D12Resource upload_buffer,
|
||||
const D3D12_PLACED_SUBRESOURCE_FOOTPRINT *layout,
|
||||
const D3D12_BOX *src_box)
|
||||
{
|
||||
D3D12_TEXTURE_COPY_LOCATION src, dst;
|
||||
d3d12_video_t* d3d12_ = (d3d12_video_t*)userdata;
|
||||
@@ -1073,9 +1080,9 @@ static void d3d12_upload_texture(D3D12GraphicsCommandList cmd,
|
||||
if (d3d12_)
|
||||
texture->upload_fence = d3d12_->queue.fenceValue + 1;
|
||||
|
||||
src.pResource = texture->upload_buffer;
|
||||
src.pResource = upload_buffer;
|
||||
src.Type = D3D12_TEXTURE_COPY_TYPE_PLACED_FOOTPRINT;
|
||||
src.PlacedFootprint = texture->layout;
|
||||
src.PlacedFootprint = *layout;
|
||||
|
||||
dst.pResource = texture->handle;
|
||||
dst.Type = D3D12_TEXTURE_COPY_TYPE_SUBRESOURCE_INDEX;
|
||||
@@ -1087,7 +1094,7 @@ static void d3d12_upload_texture(D3D12GraphicsCommandList cmd,
|
||||
D3D12_RESOURCE_STATE_PIXEL_SHADER_RESOURCE,
|
||||
D3D12_RESOURCE_STATE_COPY_DEST);
|
||||
|
||||
cmd->lpVtbl->CopyTextureRegion(cmd, &dst, 0, 0, 0, &src, NULL);
|
||||
cmd->lpVtbl->CopyTextureRegion(cmd, &dst, 0, 0, 0, &src, src_box);
|
||||
|
||||
D3D12_RESOURCE_TRANSITION(
|
||||
cmd,
|
||||
@@ -1157,6 +1164,13 @@ static void d3d12_upload_texture(D3D12GraphicsCommandList cmd,
|
||||
texture->dirty = false;
|
||||
}
|
||||
|
||||
static void d3d12_upload_texture(D3D12GraphicsCommandList cmd,
|
||||
d3d12_texture_t* texture, void *userdata)
|
||||
{
|
||||
d3d12_upload_texture_from(cmd, texture, userdata,
|
||||
texture->upload_buffer, &texture->layout, NULL);
|
||||
}
|
||||
|
||||
static void d3d12_update_texture(
|
||||
int width,
|
||||
int height,
|
||||
@@ -5834,6 +5848,48 @@ static INLINE void d3d12_wait_for_vblank(d3d12_video_t* d3d12)
|
||||
}
|
||||
}
|
||||
|
||||
/* Where a pushed frame lies in the lent framebuffer.
|
||||
*
|
||||
* True, with the box to copy, when @frame at @pitch with the size
|
||||
* @width x @height is inside d3d12->sw_fb's mapping, on its row pitch
|
||||
* and whole: the whole loan pushed back, or a window into it. The
|
||||
* same test the Vulkan driver and the threaded wrapper make. */
|
||||
static bool d3d12_sw_fb_window(d3d12_video_t *d3d12,
|
||||
const void *frame, unsigned width, unsigned height,
|
||||
unsigned pitch, D3D12_BOX *box)
|
||||
{
|
||||
uintptr_t base, p;
|
||||
size_t off, row, bytes;
|
||||
unsigned bpp, x, y;
|
||||
unsigned row_pitch;
|
||||
|
||||
if (!d3d12->sw_fb.buffer || !d3d12->sw_fb.mapped)
|
||||
return false;
|
||||
base = (uintptr_t)d3d12->sw_fb.mapped + d3d12->sw_fb.layout.Offset;
|
||||
p = (uintptr_t)frame;
|
||||
bytes = (size_t)(d3d12->sw_fb.total_bytes - d3d12->sw_fb.layout.Offset);
|
||||
row_pitch = d3d12->sw_fb.layout.Footprint.RowPitch;
|
||||
if (p < base || p - base >= bytes || pitch != row_pitch)
|
||||
return false;
|
||||
bpp = (d3d12->sw_fb.format == DXGI_FORMAT_B8G8R8X8_UNORM) ? 4 : 2;
|
||||
off = (size_t)(p - base);
|
||||
row = off % row_pitch;
|
||||
if (row % bpp)
|
||||
return false;
|
||||
y = (unsigned)(off / row_pitch);
|
||||
x = (unsigned)(row / bpp);
|
||||
if ( x + width > d3d12->sw_fb.layout.Footprint.Width
|
||||
|| y + height > d3d12->sw_fb.layout.Footprint.Height)
|
||||
return false;
|
||||
box->left = x;
|
||||
box->top = y;
|
||||
box->front = 0;
|
||||
box->right = x + width;
|
||||
box->bottom = y + height;
|
||||
box->back = 1;
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool d3d12_gfx_frame(
|
||||
void* data,
|
||||
const void* frame,
|
||||
@@ -6218,10 +6274,9 @@ static bool d3d12_gfx_frame(
|
||||
/* History rotation moves texture[0] to a history slot,
|
||||
* but the SW framebuffer the core wrote into lives in
|
||||
* the separate d3d12->sw_fb buffer, not in any of the
|
||||
* rotated d3d12_texture_t slots. Rotation therefore
|
||||
* leaves SW_FRAMEBUFFER_READY validly set, and the GPU
|
||||
* upload below sources from sw_fb.buffer regardless of
|
||||
* which physical texture is in the front slot. */
|
||||
* rotated d3d12_texture_t slots, so the GPU upload below
|
||||
* sources from sw_fb.buffer regardless of which physical
|
||||
* texture is in the front slot. */
|
||||
}
|
||||
}
|
||||
|
||||
@@ -6232,6 +6287,7 @@ static bool d3d12_gfx_frame(
|
||||
d3d12->frame.texture[0].desc.Width = width;
|
||||
d3d12->frame.texture[0].desc.Height = height;
|
||||
d3d12->frame.texture[0].srv_heap = &d3d12->desc.srv_heap;
|
||||
GFX_INSTR_INC(GFX_INSTR_FRAME_TEX_CREATE);
|
||||
d3d12_release_texture(&d3d12->frame.texture[0]);
|
||||
d3d12_init_texture(d3d12->device, &d3d12->frame.texture[0]);
|
||||
|
||||
@@ -6326,28 +6382,25 @@ static bool d3d12_gfx_frame(
|
||||
}
|
||||
else
|
||||
{
|
||||
if (d3d12->flags & D3D12_ST_FLAG_SW_FRAMEBUFFER_READY)
|
||||
D3D12_BOX window;
|
||||
/* A frame the core rendered into the lent framebuffer
|
||||
* (d3d12->sw_fb) is read out of it by the GPU. Decided by
|
||||
* where the pushed pointer lies, not by whether the loan was
|
||||
* asked for: a core may ask and then push its own buffer, or
|
||||
* a dupe, and a core that crops overscan by offset pushes a
|
||||
* pointer partway into the loan with the window's size
|
||||
* (beetle-psx does) - the copy takes that window. */
|
||||
if (d3d12_sw_fb_window(d3d12, frame, width, height, pitch,
|
||||
&window))
|
||||
{
|
||||
/* Core wrote directly into the cached SW FB buffer
|
||||
* (d3d12->sw_fb). GPU-copy from there into the front
|
||||
* frame texture by temporarily pointing texture[0]'s
|
||||
* upload_buffer / layout at sw_fb's, calling the
|
||||
* standard upload helper, then restoring -- this reuses
|
||||
* the existing CopyTextureRegion + mipmap-generate
|
||||
* plumbing without a signature change. */
|
||||
D3D12Resource saved_buf
|
||||
= d3d12->frame.texture[0].upload_buffer;
|
||||
D3D12_PLACED_SUBRESOURCE_FOOTPRINT saved_layout
|
||||
= d3d12->frame.texture[0].layout;
|
||||
d3d12->frame.texture[0].upload_buffer = d3d12->sw_fb.buffer;
|
||||
d3d12->frame.texture[0].layout = d3d12->sw_fb.layout;
|
||||
d3d12_upload_texture(cmd, &d3d12->frame.texture[0], d3d12);
|
||||
d3d12->frame.texture[0].upload_buffer = saved_buf;
|
||||
d3d12->frame.texture[0].layout = saved_layout;
|
||||
d3d12->flags &= ~D3D12_ST_FLAG_SW_FRAMEBUFFER_READY;
|
||||
GFX_INSTR_INC(GFX_INSTR_FRAME_LENT_WINDOW);
|
||||
d3d12_upload_texture_from(cmd, &d3d12->frame.texture[0],
|
||||
d3d12, d3d12->sw_fb.buffer, &d3d12->sw_fb.layout,
|
||||
&window);
|
||||
}
|
||||
else
|
||||
{
|
||||
GFX_INSTR_INC(GFX_INSTR_FRAME_COPY_HOST);
|
||||
if (d3d12->frame.texture[0].upload_buffer)
|
||||
d3d12_update_texture(width, height, pitch, d3d12->format,
|
||||
frame, &d3d12->frame.texture[0]);
|
||||
@@ -8589,10 +8642,10 @@ static bool d3d12_get_current_software_framebuffer(
|
||||
* to its own staging buffer. */
|
||||
fb->memory_flags = RETRO_MEMORY_TYPE_CACHED;
|
||||
|
||||
/* Signal d3d12_gfx_frame that the core wrote directly into
|
||||
* the cached SW FB buffer; the GPU copy at upload time should
|
||||
* source from there instead of texture[0].upload_buffer. */
|
||||
d3d12->flags |= D3D12_ST_FLAG_SW_FRAMEBUFFER_READY;
|
||||
/* d3d12_gfx_frame() recognises a frame pushed from this buffer
|
||||
* by its pointer (d3d12_sw_fb_window) and has the GPU read it
|
||||
* from here; nothing is flagged, so a core that asks and then
|
||||
* pushes its own buffer, or a dupe, is served as it pushed. */
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
+212
-25
@@ -2246,14 +2246,20 @@ static struct vk_texture vulkan_create_texture(vk_t *vk,
|
||||
/* Dynamic texture type should be set to : VULKAN_TEXTURE_DYNAMIC
|
||||
* Staging texture type should be set to : VULKAN_TEXTURE_STAGING
|
||||
*/
|
||||
/* Fill @dynamic from the staging buffer, starting @src_x, @src_y texels
|
||||
* into it: (0, 0) for a frame that fills the buffer, the window's
|
||||
* origin for a frame pushed as a window into a lent buffer. The
|
||||
* staging buffer's row pitch is @staging->stride either way. */
|
||||
static void vulkan_copy_staging_to_dynamic(vk_t *vk, VkCommandBuffer cmd,
|
||||
struct vk_texture *dynamic, struct vk_texture *staging)
|
||||
struct vk_texture *dynamic, struct vk_texture *staging,
|
||||
unsigned src_x, unsigned src_y)
|
||||
{
|
||||
bool compute_upload = dynamic->format != staging->format;
|
||||
unsigned bpp = vulkan_format_to_bpp(staging->format);
|
||||
|
||||
if (compute_upload)
|
||||
{
|
||||
uint32_t ubo[3];
|
||||
uint32_t ubo[4];
|
||||
VkWriteDescriptorSet write;
|
||||
VkDescriptorBufferInfo buffer_info;
|
||||
VkDescriptorImageInfo image_info;
|
||||
@@ -2263,6 +2269,10 @@ static void vulkan_copy_staging_to_dynamic(vk_t *vk, VkCommandBuffer cmd,
|
||||
ubo[0] = VIDEO_SCALE_W(dynamic->dims);
|
||||
ubo[1] = VIDEO_SCALE_H(dynamic->dims);
|
||||
ubo[2] = (uint32_t)(staging->stride / 4); /* in terms of u32 words */
|
||||
/* The shader converts pixel pairs, one word each, so the window
|
||||
* has to start on a pair: vulkan_frame_window() only reports a
|
||||
* window whose byte origin is word-aligned. */
|
||||
ubo[3] = (uint32_t)((src_y * staging->stride + (size_t)src_x * bpp) / 4);
|
||||
|
||||
VULKAN_IMAGE_LAYOUT_TRANSITION(
|
||||
cmd,
|
||||
@@ -2352,8 +2362,12 @@ static void vulkan_copy_staging_to_dynamic(vk_t *vk, VkCommandBuffer cmd,
|
||||
VK_ACCESS_TRANSFER_WRITE_BIT,
|
||||
VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT,
|
||||
VK_PIPELINE_STAGE_TRANSFER_BIT);
|
||||
region.bufferOffset = 0;
|
||||
region.bufferRowLength = 0;
|
||||
region.bufferOffset =
|
||||
src_y * staging->stride + (size_t)src_x * bpp;
|
||||
/* The buffer's row pitch in texels. 0 means tightly packed at
|
||||
* the image width, which a window into a wider buffer is not. */
|
||||
region.bufferRowLength =
|
||||
(uint32_t)(staging->stride / bpp);
|
||||
region.bufferImageHeight = 0;
|
||||
region.imageSubresource.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
|
||||
region.imageSubresource.mipLevel = 0;
|
||||
@@ -2385,6 +2399,103 @@ static void vulkan_copy_staging_to_dynamic(vk_t *vk, VkCommandBuffer cmd,
|
||||
dynamic->layout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL;
|
||||
}
|
||||
|
||||
/* Fill @dynamic from a window into the streamed (linear, host-mapped)
|
||||
* image @linear, starting @src_x, @src_y texels in. Both are images of
|
||||
* the same format, so this is a plain transfer; the host's writes to
|
||||
* the loan were made before this submission, and queue submission
|
||||
* makes them visible to it. */
|
||||
static void vulkan_copy_linear_to_dynamic(vk_t *vk, VkCommandBuffer cmd,
|
||||
struct vk_texture *dynamic, struct vk_texture *linear,
|
||||
unsigned src_x, unsigned src_y)
|
||||
{
|
||||
VkImageCopy region;
|
||||
|
||||
/* A streamed image is sampled in GENERAL, and is read as a
|
||||
* transfer source in GENERAL as well. */
|
||||
vulkan_transition_texture(vk, cmd, linear);
|
||||
|
||||
VULKAN_IMAGE_LAYOUT_TRANSITION(
|
||||
cmd,
|
||||
dynamic->image,
|
||||
VK_IMAGE_LAYOUT_UNDEFINED,
|
||||
VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL,
|
||||
0,
|
||||
VK_ACCESS_TRANSFER_WRITE_BIT,
|
||||
VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT,
|
||||
VK_PIPELINE_STAGE_TRANSFER_BIT);
|
||||
|
||||
region.srcSubresource.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
|
||||
region.srcSubresource.mipLevel = 0;
|
||||
region.srcSubresource.baseArrayLayer = 0;
|
||||
region.srcSubresource.layerCount = 1;
|
||||
region.srcOffset.x = (int32_t)src_x;
|
||||
region.srcOffset.y = (int32_t)src_y;
|
||||
region.srcOffset.z = 0;
|
||||
region.dstSubresource = region.srcSubresource;
|
||||
region.dstOffset.x = 0;
|
||||
region.dstOffset.y = 0;
|
||||
region.dstOffset.z = 0;
|
||||
region.extent.width = VIDEO_SCALE_W(dynamic->dims);
|
||||
region.extent.height = VIDEO_SCALE_H(dynamic->dims);
|
||||
region.extent.depth = 1;
|
||||
vkCmdCopyImage(cmd,
|
||||
linear->image, VK_IMAGE_LAYOUT_GENERAL,
|
||||
dynamic->image, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL,
|
||||
1, ®ion);
|
||||
|
||||
VULKAN_IMAGE_LAYOUT_TRANSITION(
|
||||
cmd,
|
||||
dynamic->image,
|
||||
VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL,
|
||||
VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL,
|
||||
VK_ACCESS_TRANSFER_WRITE_BIT,
|
||||
VK_ACCESS_SHADER_READ_BIT,
|
||||
VK_PIPELINE_STAGE_TRANSFER_BIT,
|
||||
VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT);
|
||||
dynamic->layout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL;
|
||||
}
|
||||
|
||||
/* Where a pushed frame lies in a lent texture.
|
||||
*
|
||||
* A core that renders into the buffer GET_CURRENT_SOFTWARE_FRAMEBUFFER
|
||||
* lent it may push back a pointer partway into that buffer, at the
|
||||
* buffer's pitch, with the size of the window it wants shown: that is
|
||||
* how an overscan crop is done by offset (beetle-psx renders its
|
||||
* whole 700x480 scanout surface into the loan and pushes the visible
|
||||
* part). The threaded wrapper accepts that as a lend since
|
||||
* 9ed0db58c3; this is the same test for the driver's own loan.
|
||||
*
|
||||
* True, with the window's texel origin, when @frame at @pitch with
|
||||
* the size @dims is such a window into @tex: inside its mapping, on
|
||||
* the mapping's pitch, whole, and starting on a word so the RGB565
|
||||
* compute upload can address it. Anything else is a frame of the
|
||||
* core's own, or of another texture, and is uploaded by copying. */
|
||||
static bool vulkan_frame_window(const struct vk_texture *tex,
|
||||
const void *frame, unsigned dims, size_t pitch,
|
||||
unsigned *x, unsigned *y)
|
||||
{
|
||||
uintptr_t base = (uintptr_t)tex->mapped;
|
||||
uintptr_t p = (uintptr_t)frame;
|
||||
size_t off, row;
|
||||
unsigned bpp;
|
||||
|
||||
if (!tex->mapped || !tex->stride || p < base || p - base >= tex->size)
|
||||
return false;
|
||||
if (pitch != tex->stride)
|
||||
return false;
|
||||
bpp = vulkan_format_to_bpp(tex->format);
|
||||
off = (size_t)(p - base);
|
||||
row = off % tex->stride;
|
||||
if ((row % bpp) || (off & 3))
|
||||
return false;
|
||||
*y = (unsigned)(off / tex->stride);
|
||||
*x = (unsigned)(row / bpp);
|
||||
if ( *x + VIDEO_SCALE_W(dims) > VIDEO_SCALE_W(tex->dims)
|
||||
|| *y + VIDEO_SCALE_H(dims) > VIDEO_SCALE_H(tex->dims))
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* FORWARD DECLARATIONS
|
||||
*/
|
||||
@@ -8135,12 +8246,36 @@ static bool vulkan_frame(void *data, const void *frame,
|
||||
unsigned y;
|
||||
unsigned frame_width = VIDEO_SCALE_W(dims);
|
||||
unsigned frame_height = VIDEO_SCALE_H(dims);
|
||||
uint8_t *dst = NULL;
|
||||
const uint8_t *src = (const uint8_t*)frame;
|
||||
unsigned bpp = vk->video.rgb32 ? 4 : 2;
|
||||
unsigned win_x = 0;
|
||||
unsigned win_y = 0;
|
||||
uint8_t *dst = NULL;
|
||||
const uint8_t *src = (const uint8_t*)frame;
|
||||
unsigned bpp = vk->video.rgb32 ? 4 : 2;
|
||||
bool retire_cached = false;
|
||||
/* A window into this texture's own loan: the pixels are already
|
||||
* where the GPU reads them, and the texture keeps the loan's
|
||||
* size for the next lend. The window is cut out on the GPU into
|
||||
* texture_optimal, which is what gets sampled. Nothing is
|
||||
* recreated per frame, and the mapping the cached frame points
|
||||
* into stays mapped. */
|
||||
bool window = vulkan_frame_window(&chain->texture,
|
||||
frame, dims, pitch, &win_x, &win_y);
|
||||
|
||||
if (chain->texture.dims != dims)
|
||||
if (!window && chain->texture.dims != dims)
|
||||
{
|
||||
/* A frame inside this texture's mapping that is not a window
|
||||
* into it (another pitch, or it would not fit) is copied out
|
||||
* below before the mapping goes, but the mapping goes only
|
||||
* frames later, off the deferred list, and the cached frame
|
||||
* still names it until then: a paused redraw would read it
|
||||
* after its release. Retire the cached frame once the copy
|
||||
* is done. */
|
||||
{
|
||||
uintptr_t base = (uintptr_t)chain->texture.mapped;
|
||||
uintptr_t p = (uintptr_t)frame;
|
||||
retire_cached = base && p >= base && p - base < chain->texture.size;
|
||||
}
|
||||
GFX_INSTR_INC(GFX_INSTR_FRAME_TEX_CREATE);
|
||||
chain->texture = vulkan_create_texture(vk, &chain->texture,
|
||||
frame_width, frame_height, chain->texture.format, NULL, NULL,
|
||||
chain->texture_optimal.memory
|
||||
@@ -8152,30 +8287,74 @@ static bool vulkan_frame(void *data, const void *frame,
|
||||
}
|
||||
|
||||
if (chain->texture.type == VULKAN_TEXTURE_STAGING)
|
||||
{
|
||||
GFX_INSTR_INC(GFX_INSTR_FRAME_TEX_CREATE);
|
||||
chain->texture_optimal = vulkan_create_texture(
|
||||
vk,
|
||||
&chain->texture_optimal,
|
||||
frame_width, frame_height,
|
||||
chain->texture.format, /* Ensure we use the original format and not any remapped format. */
|
||||
NULL, NULL, VULKAN_TEXTURE_DYNAMIC);
|
||||
}
|
||||
}
|
||||
|
||||
if (frame != chain->texture.mapped)
|
||||
if (window)
|
||||
{
|
||||
dst = (uint8_t*)chain->texture.mapped;
|
||||
if (chain->texture.stride == pitch)
|
||||
/* Stride matches pitch — single contiguous copy regardless
|
||||
* of whether pitch == frame_width * bpp (there may be
|
||||
* trailing padding per row, but the layout is identical). */
|
||||
memcpy(dst, src, (size_t)chain->texture.stride * frame_height);
|
||||
else
|
||||
GFX_INSTR_INC(GFX_INSTR_FRAME_LENT_WINDOW);
|
||||
if ( chain->texture_optimal.memory == VK_NULL_HANDLE
|
||||
|| chain->texture_optimal.dims != dims)
|
||||
{
|
||||
/* Stride and pitch differ — copy each row.
|
||||
* Use the tight pixel width to avoid copying garbage. */
|
||||
unsigned row_bytes = frame_width * bpp;
|
||||
for (y = 0; y < frame_height; y++,
|
||||
dst += chain->texture.stride, src += pitch)
|
||||
memcpy(dst, src, row_bytes);
|
||||
GFX_INSTR_INC(GFX_INSTR_FRAME_TEX_CREATE);
|
||||
chain->texture_optimal = vulkan_create_texture(
|
||||
vk,
|
||||
&chain->texture_optimal,
|
||||
frame_width, frame_height,
|
||||
chain->texture.format,
|
||||
NULL, NULL, VULKAN_TEXTURE_DYNAMIC);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (frame != chain->texture.mapped)
|
||||
{
|
||||
GFX_INSTR_INC(GFX_INSTR_FRAME_COPY_HOST);
|
||||
dst = (uint8_t*)chain->texture.mapped;
|
||||
if (chain->texture.stride == pitch)
|
||||
/* Stride matches pitch — single contiguous copy regardless
|
||||
* of whether pitch == frame_width * bpp (there may be
|
||||
* trailing padding per row, but the layout is identical). */
|
||||
memcpy(dst, src, (size_t)chain->texture.stride * frame_height);
|
||||
else
|
||||
{
|
||||
/* Stride and pitch differ — copy each row.
|
||||
* Use the tight pixel width to avoid copying garbage. */
|
||||
unsigned row_bytes = frame_width * bpp;
|
||||
for (y = 0; y < frame_height; y++,
|
||||
dst += chain->texture.stride, src += pitch)
|
||||
memcpy(dst, src, row_bytes);
|
||||
}
|
||||
}
|
||||
|
||||
/* texture_optimal is sampled whenever it exists, so it has
|
||||
* to be this frame's size. A window earlier left it at the
|
||||
* window's: a staging texture is copied into it and gets one
|
||||
* at the frame's size, a streamed texture is sampled itself
|
||||
* and has no use for it. */
|
||||
if ( chain->texture_optimal.memory != VK_NULL_HANDLE
|
||||
&& chain->texture_optimal.dims != dims)
|
||||
{
|
||||
if (chain->texture.type == VULKAN_TEXTURE_STAGING)
|
||||
{
|
||||
GFX_INSTR_INC(GFX_INSTR_FRAME_TEX_CREATE);
|
||||
chain->texture_optimal = vulkan_create_texture(
|
||||
vk,
|
||||
&chain->texture_optimal,
|
||||
frame_width, frame_height,
|
||||
chain->texture.format,
|
||||
NULL, NULL, VULKAN_TEXTURE_DYNAMIC);
|
||||
}
|
||||
else
|
||||
vulkan_texture_defer_copy(vk, &chain->texture_optimal);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -8194,10 +8373,18 @@ static bool vulkan_frame(void *data, const void *frame,
|
||||
if (chain->texture_optimal.memory != VK_NULL_HANDLE)
|
||||
{
|
||||
struct vk_texture *dynamic = &chain->texture_optimal;
|
||||
struct vk_texture *staging = &chain->texture;
|
||||
vulkan_copy_staging_to_dynamic(vk, vk->cmd, dynamic, staging);
|
||||
struct vk_texture *source = &chain->texture;
|
||||
if (source->type == VULKAN_TEXTURE_STAGING)
|
||||
vulkan_copy_staging_to_dynamic(vk, vk->cmd, dynamic, source,
|
||||
win_x, win_y);
|
||||
else
|
||||
vulkan_copy_linear_to_dynamic(vk, vk->cmd, dynamic, source,
|
||||
win_x, win_y);
|
||||
}
|
||||
|
||||
if (retire_cached)
|
||||
video_driver_cached_frame_retire();
|
||||
|
||||
vk->last_valid_index = frame_index;
|
||||
}
|
||||
|
||||
@@ -8382,7 +8569,7 @@ static bool vulkan_frame(void *data, const void *frame,
|
||||
vkFlushMappedMemoryRanges(vk->context->device, 1, &range);
|
||||
}
|
||||
vulkan_copy_staging_to_dynamic(vk, vk->cmd,
|
||||
dynamic, staging);
|
||||
dynamic, staging, 0, 0);
|
||||
vk->menu.dirty[vk->menu.last_index] = false;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -12,6 +12,9 @@ layout(set = 0, binding = 0, std140) uniform UBO
|
||||
{
|
||||
uvec2 resolution;
|
||||
uint word_stride;
|
||||
// First word of the source rectangle: a frame lent to the core
|
||||
// and pushed back as a window into the loan starts partway in.
|
||||
uint word_offset;
|
||||
};
|
||||
|
||||
vec3 rgb565_to_rgb888(uint word)
|
||||
@@ -27,7 +30,7 @@ void main()
|
||||
|
||||
if (all(lessThan(first_output_pixel, resolution)))
|
||||
{
|
||||
uint word = packed_pixels[first_input_pixel.y * word_stride + first_input_pixel.x];
|
||||
uint word = packed_pixels[word_offset + first_input_pixel.y * word_stride + first_input_pixel.x];
|
||||
uint lo_word = word & 0xffffu;
|
||||
uint hi_word = word >> 16u;
|
||||
vec3 lo = rgb565_to_rgb888(lo_word);
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
{0x07230203,0x00010000,0x000d000b,0x00000081,
|
||||
{0x07230203,0x00010000,0x000d000b,0x00000085,
|
||||
0x00000000,0x00020011,0x00000001,0x0006000b,
|
||||
0x00000001,0x4c534c47,0x6474732e,0x3035342e,
|
||||
0x00000000,0x0003000e,0x00000000,0x00000001,
|
||||
@@ -23,61 +23,64 @@
|
||||
0x0000002f,0x004f4255,0x00060006,0x0000002f,
|
||||
0x00000000,0x6f736572,0x6974756c,0x00006e6f,
|
||||
0x00060006,0x0000002f,0x00000001,0x64726f77,
|
||||
0x7274735f,0x00656469,0x00030005,0x00000031,
|
||||
0x00000000,0x00040005,0x0000003d,0x64726f77,
|
||||
0x00000000,0x00040005,0x0000003f,0x4f425353,
|
||||
0x00000000,0x00070006,0x0000003f,0x00000000,
|
||||
0x6b636170,0x705f6465,0x6c657869,0x00000073,
|
||||
0x00030005,0x00000041,0x00000000,0x00040005,
|
||||
0x0000004e,0x775f6f6c,0x0064726f,0x00040005,
|
||||
0x00000052,0x775f6968,0x0064726f,0x00030005,
|
||||
0x00000057,0x00006f6c,0x00040005,0x00000058,
|
||||
0x61726170,0x0000006d,0x00030005,0x0000005b,
|
||||
0x00006968,0x00040005,0x0000005c,0x61726170,
|
||||
0x0000006d,0x00040005,0x00000061,0x616d4975,
|
||||
0x00006567,0x00040047,0x00000025,0x0000000b,
|
||||
0x0000001c,0x00050048,0x0000002f,0x00000000,
|
||||
0x00000023,0x00000000,0x00050048,0x0000002f,
|
||||
0x00000001,0x00000023,0x00000008,0x00030047,
|
||||
0x0000002f,0x00000002,0x00040047,0x00000031,
|
||||
0x00000022,0x00000000,0x00040047,0x00000031,
|
||||
0x00000021,0x00000000,0x00040047,0x0000003e,
|
||||
0x00000006,0x00000004,0x00040048,0x0000003f,
|
||||
0x00000000,0x00000018,0x00050048,0x0000003f,
|
||||
0x00000000,0x00000023,0x00000000,0x00030047,
|
||||
0x0000003f,0x00000003,0x00040047,0x00000041,
|
||||
0x00000022,0x00000000,0x00040047,0x00000041,
|
||||
0x00000021,0x00000004,0x00040047,0x00000061,
|
||||
0x00000022,0x00000000,0x00040047,0x00000061,
|
||||
0x00000021,0x00000003,0x00030047,0x00000061,
|
||||
0x00000019,0x00040047,0x00000080,0x0000000b,
|
||||
0x00000019,0x00020013,0x00000002,0x00030021,
|
||||
0x00000003,0x00000002,0x00040015,0x00000006,
|
||||
0x00000020,0x00000000,0x00040020,0x00000007,
|
||||
0x00000007,0x00000006,0x00030016,0x00000008,
|
||||
0x00000020,0x00040017,0x00000009,0x00000008,
|
||||
0x00000003,0x00040021,0x0000000a,0x00000009,
|
||||
0x00000007,0x00040017,0x0000000f,0x00000006,
|
||||
0x00000003,0x0004002b,0x00000006,0x00000011,
|
||||
0x0000000b,0x0004002b,0x00000006,0x00000012,
|
||||
0x00000005,0x0004002b,0x00000006,0x00000013,
|
||||
0x00000000,0x0006002c,0x0000000f,0x00000014,
|
||||
0x00000011,0x00000012,0x00000013,0x0004002b,
|
||||
0x00000006,0x00000016,0x0000001f,0x0004002b,
|
||||
0x00000006,0x00000017,0x0000003f,0x0006002c,
|
||||
0x0000000f,0x00000018,0x00000016,0x00000017,
|
||||
0x00000016,0x0004002b,0x00000008,0x0000001b,
|
||||
0x41f80000,0x0004002b,0x00000008,0x0000001c,
|
||||
0x427c0000,0x0006002c,0x00000009,0x0000001d,
|
||||
0x0000001b,0x0000001c,0x0000001b,0x00040017,
|
||||
0x00000021,0x00000006,0x00000002,0x00040020,
|
||||
0x00000022,0x00000007,0x00000021,0x00040020,
|
||||
0x00000024,0x00000001,0x0000000f,0x0004003b,
|
||||
0x00000024,0x00000025,0x00000001,0x0004002b,
|
||||
0x00000006,0x0000002a,0x00000002,0x0004002b,
|
||||
0x00000006,0x0000002b,0x00000001,0x0005002c,
|
||||
0x00000021,0x0000002c,0x0000002a,0x0000002b,
|
||||
0x0004001e,0x0000002f,0x00000021,0x00000006,
|
||||
0x7274735f,0x00656469,0x00060006,0x0000002f,
|
||||
0x00000002,0x64726f77,0x66666f5f,0x00746573,
|
||||
0x00030005,0x00000031,0x00000000,0x00040005,
|
||||
0x0000003d,0x64726f77,0x00000000,0x00040005,
|
||||
0x0000003f,0x4f425353,0x00000000,0x00070006,
|
||||
0x0000003f,0x00000000,0x6b636170,0x705f6465,
|
||||
0x6c657869,0x00000073,0x00030005,0x00000041,
|
||||
0x00000000,0x00040005,0x00000052,0x775f6f6c,
|
||||
0x0064726f,0x00040005,0x00000056,0x775f6968,
|
||||
0x0064726f,0x00030005,0x0000005b,0x00006f6c,
|
||||
0x00040005,0x0000005c,0x61726170,0x0000006d,
|
||||
0x00030005,0x0000005f,0x00006968,0x00040005,
|
||||
0x00000060,0x61726170,0x0000006d,0x00040005,
|
||||
0x00000065,0x616d4975,0x00006567,0x00040047,
|
||||
0x00000025,0x0000000b,0x0000001c,0x00050048,
|
||||
0x0000002f,0x00000000,0x00000023,0x00000000,
|
||||
0x00050048,0x0000002f,0x00000001,0x00000023,
|
||||
0x00000008,0x00050048,0x0000002f,0x00000002,
|
||||
0x00000023,0x0000000c,0x00030047,0x0000002f,
|
||||
0x00000002,0x00040047,0x00000031,0x00000022,
|
||||
0x00000000,0x00040047,0x00000031,0x00000021,
|
||||
0x00000000,0x00040047,0x0000003e,0x00000006,
|
||||
0x00000004,0x00040048,0x0000003f,0x00000000,
|
||||
0x00000018,0x00050048,0x0000003f,0x00000000,
|
||||
0x00000023,0x00000000,0x00030047,0x0000003f,
|
||||
0x00000003,0x00040047,0x00000041,0x00000022,
|
||||
0x00000000,0x00040047,0x00000041,0x00000021,
|
||||
0x00000004,0x00040047,0x00000065,0x00000022,
|
||||
0x00000000,0x00040047,0x00000065,0x00000021,
|
||||
0x00000003,0x00030047,0x00000065,0x00000019,
|
||||
0x00040047,0x00000084,0x0000000b,0x00000019,
|
||||
0x00020013,0x00000002,0x00030021,0x00000003,
|
||||
0x00000002,0x00040015,0x00000006,0x00000020,
|
||||
0x00000000,0x00040020,0x00000007,0x00000007,
|
||||
0x00000006,0x00030016,0x00000008,0x00000020,
|
||||
0x00040017,0x00000009,0x00000008,0x00000003,
|
||||
0x00040021,0x0000000a,0x00000009,0x00000007,
|
||||
0x00040017,0x0000000f,0x00000006,0x00000003,
|
||||
0x0004002b,0x00000006,0x00000011,0x0000000b,
|
||||
0x0004002b,0x00000006,0x00000012,0x00000005,
|
||||
0x0004002b,0x00000006,0x00000013,0x00000000,
|
||||
0x0006002c,0x0000000f,0x00000014,0x00000011,
|
||||
0x00000012,0x00000013,0x0004002b,0x00000006,
|
||||
0x00000016,0x0000001f,0x0004002b,0x00000006,
|
||||
0x00000017,0x0000003f,0x0006002c,0x0000000f,
|
||||
0x00000018,0x00000016,0x00000017,0x00000016,
|
||||
0x0004002b,0x00000008,0x0000001b,0x41f80000,
|
||||
0x0004002b,0x00000008,0x0000001c,0x427c0000,
|
||||
0x0006002c,0x00000009,0x0000001d,0x0000001b,
|
||||
0x0000001c,0x0000001b,0x00040017,0x00000021,
|
||||
0x00000006,0x00000002,0x00040020,0x00000022,
|
||||
0x00000007,0x00000021,0x00040020,0x00000024,
|
||||
0x00000001,0x0000000f,0x0004003b,0x00000024,
|
||||
0x00000025,0x00000001,0x0004002b,0x00000006,
|
||||
0x0000002a,0x00000002,0x0004002b,0x00000006,
|
||||
0x0000002b,0x00000001,0x0005002c,0x00000021,
|
||||
0x0000002c,0x0000002a,0x0000002b,0x0005001e,
|
||||
0x0000002f,0x00000021,0x00000006,0x00000006,
|
||||
0x00040020,0x00000030,0x00000002,0x0000002f,
|
||||
0x0004003b,0x00000030,0x00000031,0x00000002,
|
||||
0x00040015,0x00000032,0x00000020,0x00000001,
|
||||
@@ -88,33 +91,34 @@
|
||||
0x00000006,0x0003001e,0x0000003f,0x0000003e,
|
||||
0x00040020,0x00000040,0x00000002,0x0000003f,
|
||||
0x0004003b,0x00000040,0x00000041,0x00000002,
|
||||
0x0004002b,0x00000032,0x00000044,0x00000001,
|
||||
0x00040020,0x00000045,0x00000002,0x00000006,
|
||||
0x0004002b,0x00000006,0x00000050,0x0000ffff,
|
||||
0x0004002b,0x00000006,0x00000054,0x00000010,
|
||||
0x00040020,0x00000056,0x00000007,0x00000009,
|
||||
0x00090019,0x0000005f,0x00000008,0x00000001,
|
||||
0x0004002b,0x00000032,0x00000042,0x00000002,
|
||||
0x00040020,0x00000043,0x00000002,0x00000006,
|
||||
0x0004002b,0x00000032,0x00000048,0x00000001,
|
||||
0x0004002b,0x00000006,0x00000054,0x0000ffff,
|
||||
0x0004002b,0x00000006,0x00000058,0x00000010,
|
||||
0x00040020,0x0000005a,0x00000007,0x00000009,
|
||||
0x00090019,0x00000063,0x00000008,0x00000001,
|
||||
0x00000000,0x00000000,0x00000000,0x00000002,
|
||||
0x00000004,0x00040020,0x00000060,0x00000000,
|
||||
0x0000005f,0x0004003b,0x00000060,0x00000061,
|
||||
0x00000000,0x00040017,0x00000064,0x00000032,
|
||||
0x00000002,0x0004002b,0x00000008,0x00000067,
|
||||
0x3f800000,0x00040017,0x00000068,0x00000008,
|
||||
0x00000004,0x0005002c,0x00000064,0x00000078,
|
||||
0x00000044,0x00000033,0x0004002b,0x00000006,
|
||||
0x0000007f,0x00000008,0x0006002c,0x0000000f,
|
||||
0x00000080,0x00000054,0x0000007f,0x0000002b,
|
||||
0x00000004,0x00040020,0x00000064,0x00000000,
|
||||
0x00000063,0x0004003b,0x00000064,0x00000065,
|
||||
0x00000000,0x00040017,0x00000068,0x00000032,
|
||||
0x00000002,0x0004002b,0x00000008,0x0000006b,
|
||||
0x3f800000,0x00040017,0x0000006c,0x00000008,
|
||||
0x00000004,0x0005002c,0x00000068,0x0000007c,
|
||||
0x00000048,0x00000033,0x0004002b,0x00000006,
|
||||
0x00000083,0x00000008,0x0006002c,0x0000000f,
|
||||
0x00000084,0x00000058,0x00000083,0x0000002b,
|
||||
0x00050036,0x00000002,0x00000004,0x00000000,
|
||||
0x00000003,0x000200f8,0x00000005,0x0004003b,
|
||||
0x00000022,0x00000023,0x00000007,0x0004003b,
|
||||
0x00000022,0x00000028,0x00000007,0x0004003b,
|
||||
0x00000007,0x0000003d,0x00000007,0x0004003b,
|
||||
0x00000007,0x0000004e,0x00000007,0x0004003b,
|
||||
0x00000007,0x00000052,0x00000007,0x0004003b,
|
||||
0x00000056,0x00000057,0x00000007,0x0004003b,
|
||||
0x00000007,0x00000058,0x00000007,0x0004003b,
|
||||
0x00000056,0x0000005b,0x00000007,0x0004003b,
|
||||
0x00000007,0x0000005c,0x00000007,0x0004003d,
|
||||
0x00000007,0x00000056,0x00000007,0x0004003b,
|
||||
0x0000005a,0x0000005b,0x00000007,0x0004003b,
|
||||
0x00000007,0x0000005c,0x00000007,0x0004003b,
|
||||
0x0000005a,0x0000005f,0x00000007,0x0004003b,
|
||||
0x00000007,0x00000060,0x00000007,0x0004003d,
|
||||
0x0000000f,0x00000026,0x00000025,0x0007004f,
|
||||
0x00000021,0x00000027,0x00000026,0x00000026,
|
||||
0x00000000,0x00000001,0x0003003e,0x00000023,
|
||||
@@ -129,74 +133,78 @@
|
||||
0x00000037,0x0000003a,0x00000039,0x000300f7,
|
||||
0x0000003c,0x00000000,0x000400fa,0x0000003a,
|
||||
0x0000003b,0x0000003c,0x000200f8,0x0000003b,
|
||||
0x00050041,0x00000007,0x00000042,0x00000023,
|
||||
0x0000002b,0x0004003d,0x00000006,0x00000043,
|
||||
0x00000042,0x00050041,0x00000045,0x00000046,
|
||||
0x00000031,0x00000044,0x0004003d,0x00000006,
|
||||
0x00000047,0x00000046,0x00050084,0x00000006,
|
||||
0x00000048,0x00000043,0x00000047,0x00050041,
|
||||
0x00000007,0x00000049,0x00000023,0x00000013,
|
||||
0x0004003d,0x00000006,0x0000004a,0x00000049,
|
||||
0x00050080,0x00000006,0x0000004b,0x00000048,
|
||||
0x0000004a,0x00060041,0x00000045,0x0000004c,
|
||||
0x00000041,0x00000033,0x0000004b,0x0004003d,
|
||||
0x00000006,0x0000004d,0x0000004c,0x0003003e,
|
||||
0x0000003d,0x0000004d,0x0004003d,0x00000006,
|
||||
0x0000004f,0x0000003d,0x000500c7,0x00000006,
|
||||
0x00000051,0x0000004f,0x00000050,0x0003003e,
|
||||
0x0000004e,0x00000051,0x0004003d,0x00000006,
|
||||
0x00000053,0x0000003d,0x000500c2,0x00000006,
|
||||
0x00000055,0x00000053,0x00000054,0x0003003e,
|
||||
0x00000052,0x00000055,0x0004003d,0x00000006,
|
||||
0x00000059,0x0000004e,0x0003003e,0x00000058,
|
||||
0x00000059,0x00050039,0x00000009,0x0000005a,
|
||||
0x0000000c,0x00000058,0x0003003e,0x00000057,
|
||||
0x0000005a,0x0004003d,0x00000006,0x0000005d,
|
||||
0x00000052,0x0003003e,0x0000005c,0x0000005d,
|
||||
0x00050039,0x00000009,0x0000005e,0x0000000c,
|
||||
0x0000005c,0x0003003e,0x0000005b,0x0000005e,
|
||||
0x0004003d,0x0000005f,0x00000062,0x00000061,
|
||||
0x0004003d,0x00000021,0x00000063,0x00000028,
|
||||
0x0004007c,0x00000064,0x00000065,0x00000063,
|
||||
0x0004003d,0x00000009,0x00000066,0x00000057,
|
||||
0x00050051,0x00000008,0x00000069,0x00000066,
|
||||
0x00000000,0x00050051,0x00000008,0x0000006a,
|
||||
0x00000066,0x00000001,0x00050051,0x00000008,
|
||||
0x0000006b,0x00000066,0x00000002,0x00070050,
|
||||
0x00000068,0x0000006c,0x00000069,0x0000006a,
|
||||
0x0000006b,0x00000067,0x00040063,0x00000062,
|
||||
0x00000065,0x0000006c,0x00050041,0x00000007,
|
||||
0x0000006d,0x00000028,0x00000013,0x0004003d,
|
||||
0x00000006,0x0000006e,0x0000006d,0x00050080,
|
||||
0x00000006,0x0000006f,0x0000006e,0x0000002b,
|
||||
0x00060041,0x00000045,0x00000070,0x00000031,
|
||||
0x00000033,0x00000013,0x0004003d,0x00000006,
|
||||
0x00000071,0x00000070,0x000500b0,0x00000037,
|
||||
0x00000072,0x0000006f,0x00000071,0x000300f7,
|
||||
0x00000074,0x00000000,0x000400fa,0x00000072,
|
||||
0x00000073,0x00000074,0x000200f8,0x00000073,
|
||||
0x0004003d,0x0000005f,0x00000075,0x00000061,
|
||||
0x0004003d,0x00000021,0x00000076,0x00000028,
|
||||
0x0004007c,0x00000064,0x00000077,0x00000076,
|
||||
0x00050080,0x00000064,0x00000079,0x00000077,
|
||||
0x00000078,0x0004003d,0x00000009,0x0000007a,
|
||||
0x0000005b,0x00050051,0x00000008,0x0000007b,
|
||||
0x0000007a,0x00000000,0x00050051,0x00000008,
|
||||
0x0000007c,0x0000007a,0x00000001,0x00050051,
|
||||
0x00000008,0x0000007d,0x0000007a,0x00000002,
|
||||
0x00070050,0x00000068,0x0000007e,0x0000007b,
|
||||
0x0000007c,0x0000007d,0x00000067,0x00040063,
|
||||
0x00000075,0x00000079,0x0000007e,0x000200f9,
|
||||
0x00000074,0x000200f8,0x00000074,0x000200f9,
|
||||
0x0000003c,0x000200f8,0x0000003c,0x000100fd,
|
||||
0x00010038,0x00050036,0x00000009,0x0000000c,
|
||||
0x00000000,0x0000000a,0x00030037,0x00000007,
|
||||
0x0000000b,0x000200f8,0x0000000d,0x0004003d,
|
||||
0x00000006,0x0000000e,0x0000000b,0x00060050,
|
||||
0x0000000f,0x00000010,0x0000000e,0x0000000e,
|
||||
0x0000000e,0x000500c2,0x0000000f,0x00000015,
|
||||
0x00000010,0x00000014,0x000500c7,0x0000000f,
|
||||
0x00000019,0x00000015,0x00000018,0x00040070,
|
||||
0x00000009,0x0000001a,0x00000019,0x00050088,
|
||||
0x00000009,0x0000001e,0x0000001a,0x0000001d,
|
||||
0x000200fe,0x0000001e,0x00010038}
|
||||
0x00050041,0x00000043,0x00000044,0x00000031,
|
||||
0x00000042,0x0004003d,0x00000006,0x00000045,
|
||||
0x00000044,0x00050041,0x00000007,0x00000046,
|
||||
0x00000023,0x0000002b,0x0004003d,0x00000006,
|
||||
0x00000047,0x00000046,0x00050041,0x00000043,
|
||||
0x00000049,0x00000031,0x00000048,0x0004003d,
|
||||
0x00000006,0x0000004a,0x00000049,0x00050084,
|
||||
0x00000006,0x0000004b,0x00000047,0x0000004a,
|
||||
0x00050080,0x00000006,0x0000004c,0x00000045,
|
||||
0x0000004b,0x00050041,0x00000007,0x0000004d,
|
||||
0x00000023,0x00000013,0x0004003d,0x00000006,
|
||||
0x0000004e,0x0000004d,0x00050080,0x00000006,
|
||||
0x0000004f,0x0000004c,0x0000004e,0x00060041,
|
||||
0x00000043,0x00000050,0x00000041,0x00000033,
|
||||
0x0000004f,0x0004003d,0x00000006,0x00000051,
|
||||
0x00000050,0x0003003e,0x0000003d,0x00000051,
|
||||
0x0004003d,0x00000006,0x00000053,0x0000003d,
|
||||
0x000500c7,0x00000006,0x00000055,0x00000053,
|
||||
0x00000054,0x0003003e,0x00000052,0x00000055,
|
||||
0x0004003d,0x00000006,0x00000057,0x0000003d,
|
||||
0x000500c2,0x00000006,0x00000059,0x00000057,
|
||||
0x00000058,0x0003003e,0x00000056,0x00000059,
|
||||
0x0004003d,0x00000006,0x0000005d,0x00000052,
|
||||
0x0003003e,0x0000005c,0x0000005d,0x00050039,
|
||||
0x00000009,0x0000005e,0x0000000c,0x0000005c,
|
||||
0x0003003e,0x0000005b,0x0000005e,0x0004003d,
|
||||
0x00000006,0x00000061,0x00000056,0x0003003e,
|
||||
0x00000060,0x00000061,0x00050039,0x00000009,
|
||||
0x00000062,0x0000000c,0x00000060,0x0003003e,
|
||||
0x0000005f,0x00000062,0x0004003d,0x00000063,
|
||||
0x00000066,0x00000065,0x0004003d,0x00000021,
|
||||
0x00000067,0x00000028,0x0004007c,0x00000068,
|
||||
0x00000069,0x00000067,0x0004003d,0x00000009,
|
||||
0x0000006a,0x0000005b,0x00050051,0x00000008,
|
||||
0x0000006d,0x0000006a,0x00000000,0x00050051,
|
||||
0x00000008,0x0000006e,0x0000006a,0x00000001,
|
||||
0x00050051,0x00000008,0x0000006f,0x0000006a,
|
||||
0x00000002,0x00070050,0x0000006c,0x00000070,
|
||||
0x0000006d,0x0000006e,0x0000006f,0x0000006b,
|
||||
0x00040063,0x00000066,0x00000069,0x00000070,
|
||||
0x00050041,0x00000007,0x00000071,0x00000028,
|
||||
0x00000013,0x0004003d,0x00000006,0x00000072,
|
||||
0x00000071,0x00050080,0x00000006,0x00000073,
|
||||
0x00000072,0x0000002b,0x00060041,0x00000043,
|
||||
0x00000074,0x00000031,0x00000033,0x00000013,
|
||||
0x0004003d,0x00000006,0x00000075,0x00000074,
|
||||
0x000500b0,0x00000037,0x00000076,0x00000073,
|
||||
0x00000075,0x000300f7,0x00000078,0x00000000,
|
||||
0x000400fa,0x00000076,0x00000077,0x00000078,
|
||||
0x000200f8,0x00000077,0x0004003d,0x00000063,
|
||||
0x00000079,0x00000065,0x0004003d,0x00000021,
|
||||
0x0000007a,0x00000028,0x0004007c,0x00000068,
|
||||
0x0000007b,0x0000007a,0x00050080,0x00000068,
|
||||
0x0000007d,0x0000007b,0x0000007c,0x0004003d,
|
||||
0x00000009,0x0000007e,0x0000005f,0x00050051,
|
||||
0x00000008,0x0000007f,0x0000007e,0x00000000,
|
||||
0x00050051,0x00000008,0x00000080,0x0000007e,
|
||||
0x00000001,0x00050051,0x00000008,0x00000081,
|
||||
0x0000007e,0x00000002,0x00070050,0x0000006c,
|
||||
0x00000082,0x0000007f,0x00000080,0x00000081,
|
||||
0x0000006b,0x00040063,0x00000079,0x0000007d,
|
||||
0x00000082,0x000200f9,0x00000078,0x000200f8,
|
||||
0x00000078,0x000200f9,0x0000003c,0x000200f8,
|
||||
0x0000003c,0x000100fd,0x00010038,0x00050036,
|
||||
0x00000009,0x0000000c,0x00000000,0x0000000a,
|
||||
0x00030037,0x00000007,0x0000000b,0x000200f8,
|
||||
0x0000000d,0x0004003d,0x00000006,0x0000000e,
|
||||
0x0000000b,0x00060050,0x0000000f,0x00000010,
|
||||
0x0000000e,0x0000000e,0x0000000e,0x000500c2,
|
||||
0x0000000f,0x00000015,0x00000010,0x00000014,
|
||||
0x000500c7,0x0000000f,0x00000019,0x00000015,
|
||||
0x00000018,0x00040070,0x00000009,0x0000001a,
|
||||
0x00000019,0x00050088,0x00000009,0x0000001e,
|
||||
0x0000001a,0x0000001d,0x000200fe,0x0000001e,
|
||||
0x00010038}
|
||||
@@ -50,7 +50,10 @@ static const char *gfx_instrument_names[GFX_INSTR_COUNT] = {
|
||||
"overlay_page",
|
||||
"overlay_page_load",
|
||||
"overlay_draw",
|
||||
"overlay_draw_alloc"
|
||||
"overlay_draw_alloc",
|
||||
"frame_tex_create",
|
||||
"frame_copy_host",
|
||||
"frame_lent_window"
|
||||
};
|
||||
|
||||
int gfx_instrument_get(enum gfx_instrument_counter c)
|
||||
|
||||
@@ -91,6 +91,11 @@ enum gfx_instrument_counter
|
||||
GFX_INSTR_OVERLAY_DRAW, /* overlay pages drawn (Vulkan) */
|
||||
GFX_INSTR_OVERLAY_DRAW_ALLOC,/* ..buffer ranges they took */
|
||||
|
||||
/* The software frame's way to the screen (Vulkan) */
|
||||
GFX_INSTR_FRAME_TEX_CREATE, /* frame textures (re)created */
|
||||
GFX_INSTR_FRAME_COPY_HOST, /* frames copied by the CPU */
|
||||
GFX_INSTR_FRAME_LENT_WINDOW, /* frames read straight out of a loan*/
|
||||
|
||||
GFX_INSTR_COUNT
|
||||
};
|
||||
|
||||
|
||||
@@ -38,6 +38,7 @@
|
||||
#include "../../../frontend/frontend_driver.h"
|
||||
#include "../../../frontend/frontend.h"
|
||||
#include "../../../gfx/video_driver.h"
|
||||
#include "../../../gfx/gfx_instrument.h"
|
||||
#include "../../../gfx/video_thread_wrapper.h"
|
||||
#include "../../../gfx/font_driver.h"
|
||||
#include "../../../menu/menu_driver.h"
|
||||
@@ -2934,6 +2935,96 @@ static void lane_zero_copy(void)
|
||||
lane_zero_copy_mode(2, "zero-copy lane, cropped window");
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------------ */
|
||||
/* Lane: a window into the driver's own loan, then a paused redraw */
|
||||
/* With threaded video off the driver lends its own texture through */
|
||||
/* GET_CURRENT_SOFTWARE_FRAMEBUFFER, and a core that crops overscan */
|
||||
/* by offset pushes a pointer partway into that loan (beetle-psx */
|
||||
/* does). The Vulkan driver used to see only a frame of another size */
|
||||
/* than its texture: it recreated the texture every frame, parked the */
|
||||
/* loan on its deferred list and copied out of it - and the cached */
|
||||
/* frame kept naming the parked mapping. Open the menu, so the core */
|
||||
/* stops and every iteration redraws the cached frame, and after the */
|
||||
/* deferral window the redraw read freed memory (RetroArch #19652). */
|
||||
/* The run must survive the paused redraws, and with the tree built */
|
||||
/* GFX_INSTRUMENT=1 the window frames must be read out of the loan */
|
||||
/* itself: no host copy, no texture created per frame. */
|
||||
/* ------------------------------------------------------------------ */
|
||||
|
||||
/* The Vulkan swapchain image cap, without the driver's header. */
|
||||
#define LENT_LANE_MAX_IMAGES 16
|
||||
|
||||
static void lane_lent_window_paused(void)
|
||||
{
|
||||
unsigned had = failures;
|
||||
dylib_t lib = runloop_state_get_ptr()->lib_handle;
|
||||
void (*use_fb)(int) = lib ? (void (*)(int))dylib_proc(lib, "harness_core_use_framebuffer") : NULL;
|
||||
unsigned (*granted)(void) = lib ? (unsigned (*)(void))dylib_proc(lib, "harness_core_fb_granted") : NULL;
|
||||
unsigned g0, g1;
|
||||
uint64_t f0, f1;
|
||||
|
||||
CHECK(use_fb && granted, "harness core lacks the framebuffer exports");
|
||||
if (!use_fb || !granted)
|
||||
return;
|
||||
|
||||
set_threaded_via_setting(false);
|
||||
if (menu_is_up())
|
||||
command_event(CMD_EVENT_MENU_TOGGLE, NULL);
|
||||
run_frames(5);
|
||||
expect_wrapper(false, "lent-window lane");
|
||||
|
||||
/* The loan comes from the driver now, and the core pushes its
|
||||
* window into it. Let the swapchain go round a few times. */
|
||||
use_fb(2);
|
||||
run_frames(3);
|
||||
#ifdef HAVE_GFX_INSTRUMENT
|
||||
gfx_instrument_reset();
|
||||
#endif
|
||||
g0 = granted();
|
||||
f0 = core_frames();
|
||||
run_frames(60);
|
||||
g1 = granted();
|
||||
f1 = core_frames();
|
||||
CHECK(g1 - g0 >= 30,
|
||||
"lent-window lane: driver granted only %u of 60 asks with threaded video off",
|
||||
g1 - g0);
|
||||
#ifdef HAVE_GFX_INSTRUMENT
|
||||
{
|
||||
int creates = gfx_instrument_get(GFX_INSTR_FRAME_TEX_CREATE);
|
||||
int copies = gfx_instrument_get(GFX_INSTR_FRAME_COPY_HOST);
|
||||
int windows = gfx_instrument_get(GFX_INSTR_FRAME_LENT_WINDOW);
|
||||
/* The core asks every frame and pushes a window on two of
|
||||
* three (the third is a dupe); the oversize frame it pushes
|
||||
* every 61st is its own buffer and is copied, as it should be. */
|
||||
CHECK(windows >= (int)((g1 - g0) * 2 / 3) - 4,
|
||||
"lent-window lane: %u grants but only %d frames read out of the loan",
|
||||
g1 - g0, windows);
|
||||
CHECK(copies <= 2,
|
||||
"lent-window lane: %d frames copied by the host out of a loan", copies);
|
||||
/* One loan-sized texture and one window-sized target per
|
||||
* swapchain image, once; not one per frame. */
|
||||
CHECK(creates <= 2 * LENT_LANE_MAX_IMAGES,
|
||||
"lent-window lane: %d frame textures created over %llu frames",
|
||||
creates, (unsigned long long)(f1 - f0));
|
||||
fprintf(stderr, "[baseline] lent-window lane: %u grants, %d windows, %d host copies, %d textures created over %llu frames\n",
|
||||
g1 - g0, windows, copies, creates, (unsigned long long)(f1 - f0));
|
||||
}
|
||||
#else
|
||||
(void)f0; (void)f1;
|
||||
#endif
|
||||
|
||||
/* Pause: the menu over a paused core redraws the cached frame,
|
||||
* which is the last window pushed, every iteration. Well past the
|
||||
* deferral window of any texture the frames above retired. */
|
||||
command_event(CMD_EVENT_MENU_TOGGLE, NULL);
|
||||
CHECK(menu_is_up(), "lent-window lane: menu did not open");
|
||||
run_frames(4 * LENT_LANE_MAX_IMAGES + 20);
|
||||
use_fb(0);
|
||||
|
||||
if (failures == had)
|
||||
fprintf(stderr, "[pass] lent-window lane, paused redraw\n");
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------------ */
|
||||
/* Lane: the pacing flag a driver sees follows the presenter */
|
||||
/* video_frame_info_t::threaded_display_pacing tells a driver its */
|
||||
@@ -3331,7 +3422,6 @@ static void lane_async_texture_load(void)
|
||||
/* ------------------------------------------------------------------ */
|
||||
|
||||
#include "../../../gfx/gfx_surface.h"
|
||||
#include "../../../gfx/gfx_instrument.h"
|
||||
#include "../../../input/input_overlay.h"
|
||||
|
||||
static unsigned surf_releases;
|
||||
@@ -4784,6 +4874,8 @@ int main(int argc, char *argv[])
|
||||
}
|
||||
lane_zero_copy();
|
||||
lane_zero_copy_ring_full();
|
||||
if (real_driver())
|
||||
lane_lent_window_paused();
|
||||
lane_pacing_flag_follows_wrapper();
|
||||
lane_surface_update();
|
||||
if (real_driver())
|
||||
|
||||
Reference in new issue
Block a user