mirror of
https://github.com/libretro/RetroArch.git
synced 2026-11-07 08:36:02 -10:00
feat(ps3): add native libretro RSX hardware rendering support
Expose an experimental libretro RSX context and versioned rendering interface for PSL1GHT cores. Present core-owned RSX textures without CPU uploads, share the command FIFO and unused host mapping, and defer allocation retirement until queued GPU work completes. Integrate context negotiation and enforce main-thread rendering. Restore frontend GPU state before compositing and use fenced per-font vertex pages to prevent oversized Ozone batches from corrupting queued text. Invalidate the vertex cache before menu and font draws. Make the RSX host allocation configurable at build time. Extend regression coverage for hardware image validation, deferred resource retirement, oversized font batches and allocation failures.
This commit is contained in:
1 parent
b0c6631384
commit
9ec7de02d3
7 files changed
+638
-5
No files matched your search
+2
-1
@@ -38,7 +38,8 @@ else
|
||||
endif
|
||||
|
||||
MACHDEP := -D__PSL1GHT__ -D__PS3__ -mcpu=cell
|
||||
CFLAGS += -Wall $(DEFINES) $(MACHDEP) $(INCLUDE)
|
||||
RSX_HOST_SIZE ?= 16777216
|
||||
CFLAGS += -Wall $(DEFINES) $(MACHDEP) $(INCLUDE) -DRSX_HOST_SIZE=$(RSX_HOST_SIZE)
|
||||
LDFLAGS := $(MACHDEP)
|
||||
LIBS += -lrt -laudio -lrsx -lgcm_sys -lnet -lio -lsysutil -lsysmodule -lm -llv2 -lnet -lnetctl -lsysfs -lcamera -lgem -lspurs
|
||||
|
||||
|
||||
+308
-2
@@ -49,6 +49,9 @@
|
||||
|
||||
#include "../../driver.h"
|
||||
#include "../../retroarch.h"
|
||||
#ifdef __PSL1GHT__
|
||||
#include <libretro_rsx.h>
|
||||
#endif
|
||||
#ifdef HAVE_THREADS
|
||||
#include "../video_thread_wrapper.h"
|
||||
#include "../display_servers/dispserv_ps3.h"
|
||||
@@ -61,6 +64,10 @@
|
||||
#define RSX_MAX_VERTICES 4
|
||||
#define RSX_MAX_TEXTURE_VERTICES 4096 /* Set > 0 for preallocated texture vertices */
|
||||
#define RSX_MAX_FONT_VERTICES 8192
|
||||
#ifdef __PSL1GHT__
|
||||
#define RSX_FONT_VERTEX_PAGES 8
|
||||
#define RSX_FONT_VERTEX_LABEL 198
|
||||
#endif
|
||||
|
||||
#define RSX_SHADER_STOCK_BLEND (RSX_MAX_SHADERS - 1)
|
||||
#define RSX_SHADER_MENU (RSX_MAX_SHADERS - 2)
|
||||
@@ -210,6 +217,14 @@ typedef struct
|
||||
bool should_resize;
|
||||
bool msg_rendering_enabled;
|
||||
bool shared_context_use;
|
||||
#ifdef __PSL1GHT__
|
||||
struct retro_hw_render_interface_rsx hw_interface;
|
||||
struct retro_hw_render_interface_rsx_v2 hw_interface_v2;
|
||||
unsigned hw_interface_version;
|
||||
struct retro_rsx_image hw_image;
|
||||
bool hw_render;
|
||||
bool hw_image_valid;
|
||||
#endif
|
||||
} rsx_t;
|
||||
|
||||
#include "../font_driver.h"
|
||||
@@ -229,7 +244,48 @@ typedef struct
|
||||
#include <defines/ps3_defines.h>
|
||||
|
||||
#define CB_SIZE 0x100000
|
||||
#define HOST_SIZE (32*1024*1024)
|
||||
#ifndef RSX_HOST_SIZE
|
||||
#define RSX_HOST_SIZE (16*1024*1024)
|
||||
#endif
|
||||
#define HOST_SIZE RSX_HOST_SIZE
|
||||
|
||||
#ifdef __PSL1GHT__
|
||||
static void *rsx_host_addr;
|
||||
|
||||
static bool rsx_set_hw_image(void *data, const struct retro_rsx_image *image)
|
||||
{
|
||||
rsx_t *rsx = (rsx_t*)data;
|
||||
if (!rsx)
|
||||
return false;
|
||||
rsx->hw_image_valid = false;
|
||||
if (!image)
|
||||
return true;
|
||||
if (!rsx->hw_render || rsx->video_info.is_threaded
|
||||
|| !image->width || !image->height
|
||||
|| image->width > 4096 || image->height > 4096
|
||||
|| image->pitch < image->width * 4
|
||||
|| (uint64_t)image->offset + (uint64_t)(image->height - 1)
|
||||
* image->pitch + image->width * 4 > 256u * 1024 * 1024)
|
||||
return false;
|
||||
rsx->hw_image = *image;
|
||||
rsx->hw_image_valid = true;
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool rsx_get_hw_render_interface(void *data,
|
||||
const struct retro_hw_render_interface **iface)
|
||||
{
|
||||
rsx_t *rsx = (rsx_t*)data;
|
||||
if (!rsx || !iface || !rsx->hw_render
|
||||
|| rsx->video_info.is_threaded || !rsx_host_addr)
|
||||
return false;
|
||||
if (rsx->hw_interface_version >= 2)
|
||||
*iface = (const struct retro_hw_render_interface*)&rsx->hw_interface_v2;
|
||||
else
|
||||
*iface = (const struct retro_hw_render_interface*)&rsx->hw_interface;
|
||||
return true;
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef __PSL1GHT__
|
||||
#include <rsx/rsx.h>
|
||||
@@ -242,6 +298,61 @@ typedef struct
|
||||
#include <io/pad.h>
|
||||
#endif
|
||||
|
||||
#ifdef __PSL1GHT__
|
||||
#define RSX_RETIRED_MEMORY_COUNT 256
|
||||
#define RSX_RETIRED_MEMORY_LABEL 199
|
||||
static struct
|
||||
{
|
||||
void *memory;
|
||||
uint32_t fence;
|
||||
} rsx_retired_memory[RSX_RETIRED_MEMORY_COUNT];
|
||||
static unsigned rsx_retired_memory_count;
|
||||
static uint32_t rsx_retired_memory_serial;
|
||||
static bool rsx_retired_memory_initialized;
|
||||
|
||||
static void rsx_collect_retired_memory(void)
|
||||
{
|
||||
unsigned i, kept = 0;
|
||||
uint32_t done;
|
||||
if (!rsx_retired_memory_count)
|
||||
return;
|
||||
done = *(volatile uint32_t*)gcmGetLabelAddress(RSX_RETIRED_MEMORY_LABEL);
|
||||
for (i = 0; i < rsx_retired_memory_count; i++)
|
||||
if ((int32_t)(done - rsx_retired_memory[i].fence) >= 0)
|
||||
rsxFree(rsx_retired_memory[i].memory);
|
||||
else
|
||||
rsx_retired_memory[kept++] = rsx_retired_memory[i];
|
||||
rsx_retired_memory_count = kept;
|
||||
}
|
||||
|
||||
static bool rsx_retire_hw_memory(void *data, void *memory)
|
||||
{
|
||||
rsx_t *rsx = (rsx_t*)data;
|
||||
uint32_t fence;
|
||||
if (!memory)
|
||||
return true;
|
||||
if (!rsx || !rsx->hw_render || rsx->video_info.is_threaded)
|
||||
return false;
|
||||
rsx_collect_retired_memory();
|
||||
if (rsx_retired_memory_count == RSX_RETIRED_MEMORY_COUNT)
|
||||
return false;
|
||||
if (!rsx_retired_memory_initialized)
|
||||
{
|
||||
*(volatile uint32_t*)gcmGetLabelAddress(RSX_RETIRED_MEMORY_LABEL) = 0;
|
||||
rsx_retired_memory_initialized = true;
|
||||
}
|
||||
fence = ++rsx_retired_memory_serial;
|
||||
if (!fence)
|
||||
fence = ++rsx_retired_memory_serial;
|
||||
rsx_retired_memory[rsx_retired_memory_count].memory = memory;
|
||||
rsx_retired_memory[rsx_retired_memory_count++].fence = fence;
|
||||
rsxSetWaitForIdle(rsx->context);
|
||||
rsxSetWriteBackendLabel(rsx->context, RSX_RETIRED_MEMORY_LABEL, fence);
|
||||
rsxFlushBuffer(rsx->context);
|
||||
return true;
|
||||
}
|
||||
#endif
|
||||
|
||||
#define rsx_context_bind_hw_render(rsx, enable) \
|
||||
if (rsx->shared_context_use) \
|
||||
rsx->ctx_driver->bind_hw_render(rsx->ctx_data, enable)
|
||||
@@ -254,10 +365,27 @@ typedef struct
|
||||
|
||||
#define MAX_MSG_LEN_CHUNK 64
|
||||
|
||||
#ifdef __PSL1GHT__
|
||||
typedef struct
|
||||
{
|
||||
rsx_vertex_t *vertices;
|
||||
unsigned capacity;
|
||||
unsigned used;
|
||||
u32 fence;
|
||||
} rsx_font_vertex_page_t;
|
||||
|
||||
static u32 rsx_font_vertex_serial;
|
||||
static bool rsx_font_vertex_label_initialized;
|
||||
#endif
|
||||
|
||||
typedef struct
|
||||
{
|
||||
rsx_t *rsx;
|
||||
rsx_vertex_t *vertices;
|
||||
#ifdef __PSL1GHT__
|
||||
rsx_font_vertex_page_t vertex_pages[RSX_FONT_VERTEX_PAGES];
|
||||
unsigned vertex_page;
|
||||
#endif
|
||||
rsx_texture_t texture;
|
||||
rsxProgramConst *proj_matrix;
|
||||
rsxProgramAttrib *pos_index;
|
||||
@@ -454,6 +582,9 @@ static void gfx_display_rsx_draw(gfx_display_ctx_draw_t *draw,
|
||||
GCM_LOCATION_RSX);
|
||||
|
||||
rsxClearSurface(rsx->context, GCM_CLEAR_Z);
|
||||
#ifdef __PSL1GHT__
|
||||
rsxInvalidateVertexCache(rsx->context);
|
||||
#endif
|
||||
rsxDrawVertexArray(rsx->context, GCM_TYPE_TRIANGLE_STRIP, 0, draw->coords->vertices);
|
||||
}
|
||||
|
||||
@@ -542,8 +673,17 @@ static void rsx_font_free(void *data,
|
||||
for (i = 0; i < font->retired_count; i++)
|
||||
rsxFree(font->retired[i]);
|
||||
}
|
||||
#ifdef __PSL1GHT__
|
||||
{
|
||||
unsigned i;
|
||||
for (i = 0; i < RSX_FONT_VERTEX_PAGES; i++)
|
||||
if (font->vertex_pages[i].vertices)
|
||||
rsxFree(font->vertex_pages[i].vertices);
|
||||
}
|
||||
#else
|
||||
if (font->vertices)
|
||||
rsxFree(font->vertices);
|
||||
#endif
|
||||
|
||||
free(font);
|
||||
}
|
||||
@@ -648,6 +788,15 @@ static void *rsx_font_init(void *data,
|
||||
if (!(font->vertices = (rsx_vertex_t *)rsxMemalign(128,
|
||||
sizeof(rsx_vertex_t) * RSX_MAX_FONT_VERTICES)))
|
||||
goto error;
|
||||
#ifdef __PSL1GHT__
|
||||
font->vertex_pages[0].vertices = font->vertices;
|
||||
font->vertex_pages[0].capacity = RSX_MAX_FONT_VERTICES;
|
||||
if (!rsx_font_vertex_label_initialized)
|
||||
{
|
||||
*(volatile u32*)gcmGetLabelAddress(RSX_FONT_VERTEX_LABEL) = 0;
|
||||
rsx_font_vertex_label_initialized = true;
|
||||
}
|
||||
#endif
|
||||
font->rsx->font_vert_idx = 0;
|
||||
|
||||
/* The atlas may grow; the texture follows it */
|
||||
@@ -683,6 +832,58 @@ static int rsx_font_get_message_width(void *data, const char *msg,
|
||||
font->font_data, msg, msg_len, scale);
|
||||
}
|
||||
|
||||
#ifdef __PSL1GHT__
|
||||
static bool rsx_font_reserve_vertices(rsx_t *rsx, rsx_font_t *font,
|
||||
unsigned count)
|
||||
{
|
||||
rsx_font_vertex_page_t *page = &font->vertex_pages[font->vertex_page];
|
||||
unsigned i;
|
||||
u32 done;
|
||||
|
||||
if (!count || count > (u32)-1 / sizeof(rsx_vertex_t))
|
||||
return false;
|
||||
if (!page->fence && count <= page->capacity - page->used)
|
||||
return true;
|
||||
|
||||
if (page->used && !page->fence)
|
||||
{
|
||||
page->fence = ++rsx_font_vertex_serial;
|
||||
if (!page->fence)
|
||||
page->fence = ++rsx_font_vertex_serial;
|
||||
rsxSetWriteBackendLabel(rsx->context, RSX_FONT_VERTEX_LABEL,
|
||||
page->fence);
|
||||
rsxFlushBuffer(rsx->context);
|
||||
}
|
||||
|
||||
done = *(volatile u32*)gcmGetLabelAddress(RSX_FONT_VERTEX_LABEL);
|
||||
for (i = 0; i < RSX_FONT_VERTEX_PAGES; i++)
|
||||
{
|
||||
page = &font->vertex_pages[i];
|
||||
if (page->vertices && (!page->fence
|
||||
|| (int32_t)(done - page->fence) < 0))
|
||||
continue;
|
||||
if (page->capacity < count)
|
||||
{
|
||||
unsigned capacity = MAX(count, RSX_MAX_FONT_VERTICES);
|
||||
rsx_vertex_t *vertices = (rsx_vertex_t*)rsxMemalign(128,
|
||||
capacity * sizeof(rsx_vertex_t));
|
||||
if (!vertices)
|
||||
return false;
|
||||
if (page->vertices)
|
||||
rsxFree(page->vertices);
|
||||
page->vertices = vertices;
|
||||
page->capacity = capacity;
|
||||
}
|
||||
page->used = 0;
|
||||
page->fence = 0;
|
||||
font->vertices = page->vertices;
|
||||
font->vertex_page = i;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
#endif
|
||||
|
||||
static void rsx_font_draw_vertices(
|
||||
rsx_t *rsx,
|
||||
rsx_font_t *font,
|
||||
@@ -700,13 +901,19 @@ static void rsx_font_draw_vertices(
|
||||
font->atlas->dirty = false;
|
||||
}
|
||||
|
||||
#ifdef __PSL1GHT__
|
||||
if (!rsx_font_reserve_vertices(rsx, font, coords->vertices))
|
||||
return;
|
||||
rsx->font_vert_idx = font->vertex_pages[font->vertex_page].used;
|
||||
end_vert_idx = rsx->font_vert_idx + coords->vertices;
|
||||
#else
|
||||
end_vert_idx = rsx->font_vert_idx + coords->vertices;
|
||||
if (end_vert_idx > RSX_MAX_FONT_VERTICES)
|
||||
{
|
||||
rsx->font_vert_idx = 0;
|
||||
end_vert_idx = rsx->font_vert_idx + coords->vertices;
|
||||
}
|
||||
|
||||
#endif
|
||||
vertices = font->vertices;
|
||||
|
||||
for (i = rsx->font_vert_idx; i < end_vert_idx; i++)
|
||||
@@ -725,6 +932,9 @@ static void rsx_font_draw_vertices(
|
||||
rsxAddressToOffset(&vertices[rsx->font_vert_idx].u, &font->uv_offset);
|
||||
rsxAddressToOffset(&vertices[rsx->font_vert_idx].r, &font->col_offset);
|
||||
rsx->font_vert_idx = end_vert_idx;
|
||||
#ifdef __PSL1GHT__
|
||||
font->vertex_pages[font->vertex_page].used = end_vert_idx;
|
||||
#endif
|
||||
|
||||
rsxBindVertexArrayAttrib(rsx->context, font->pos_index->index, 0,
|
||||
font->pos_offset, sizeof(rsx_vertex_t), 2,
|
||||
@@ -743,6 +953,9 @@ static void rsx_font_draw_vertices(
|
||||
font->fp_offset, GCM_LOCATION_RSX);
|
||||
|
||||
rsxClearSurface(rsx->context, GCM_CLEAR_Z);
|
||||
#ifdef __PSL1GHT__
|
||||
rsxInvalidateVertexCache(rsx->context);
|
||||
#endif
|
||||
rsxDrawVertexArray(rsx->context, GCM_TYPE_TRIANGLES, 0, coords->vertices);
|
||||
}
|
||||
|
||||
@@ -1188,6 +1401,12 @@ static const gfx_ctx_driver_t* rsx_get_context(rsx_t* rsx)
|
||||
&& (hwr->context_type != RETRO_HW_CONTEXT_NONE))
|
||||
rsx->shared_context_use = true;
|
||||
|
||||
#ifdef __PSL1GHT__
|
||||
/* Native RSX uses one command FIFO, not separate GL contexts. */
|
||||
if (hwr->context_type == RETRO_HW_CONTEXT_RSX)
|
||||
rsx->shared_context_use = false;
|
||||
#endif
|
||||
|
||||
gfx_ctx = video_context_driver_init_first(rsx,
|
||||
settings->arrays.video_context_driver,
|
||||
api, 1, 0, rsx->shared_context_use, &ctx_data);
|
||||
@@ -1307,6 +1526,9 @@ static gcmContextData *rsx_init_screen(rsx_t* gcm)
|
||||
if (!context)
|
||||
goto error;
|
||||
saved_context = context;
|
||||
#ifdef __PSL1GHT__
|
||||
rsx_host_addr = host_addr;
|
||||
#endif
|
||||
}
|
||||
else
|
||||
context = saved_context;
|
||||
@@ -1579,6 +1801,23 @@ static void* rsx_init(const video_info_t* video)
|
||||
if (video->font_enable)
|
||||
rsx->msg_rendering_enabled = true;
|
||||
|
||||
#ifdef __PSL1GHT__
|
||||
rsx->hw_render = video_driver_get_hw_context()->context_type
|
||||
== RETRO_HW_CONTEXT_RSX;
|
||||
rsx->hw_interface.interface_type = RETRO_HW_RENDER_INTERFACE_RSX;
|
||||
rsx->hw_interface.interface_version = RETRO_HW_RENDER_INTERFACE_RSX_VERSION;
|
||||
rsx->hw_interface.handle = rsx;
|
||||
rsx->hw_interface.context = rsx->context;
|
||||
rsx->hw_interface.io_address = rsx_host_addr;
|
||||
rsx->hw_interface.io_size = HOST_SIZE;
|
||||
rsx->hw_interface.io_used = CB_SIZE + 64 * 1024;
|
||||
rsx->hw_interface.set_image = rsx_set_hw_image;
|
||||
rsx->hw_interface_v2.base = rsx->hw_interface;
|
||||
rsx->hw_interface_v2.base.interface_version = RETRO_HW_RENDER_INTERFACE_RSX_V2_VERSION;
|
||||
rsx->hw_interface_v2.retire_memory = rsx_retire_hw_memory;
|
||||
rsx->hw_interface_version = video_driver_get_hw_context()->version_major;
|
||||
rsx_collect_retired_memory();
|
||||
#endif
|
||||
return rsx;
|
||||
|
||||
error:
|
||||
@@ -2414,6 +2653,34 @@ static bool rsx_frame(void* data, const void* frame,
|
||||
#endif
|
||||
bool draw = false;
|
||||
|
||||
#ifdef __PSL1GHT__
|
||||
rsx_collect_retired_memory();
|
||||
if (gcm->hw_render)
|
||||
{
|
||||
unsigned attrib;
|
||||
rsxSetSurface(gcm->context, &gcm->surface[gcm->nextBuffer]);
|
||||
rsxSetColorMask(gcm->context, GCM_COLOR_MASK_R | GCM_COLOR_MASK_G
|
||||
| GCM_COLOR_MASK_B | GCM_COLOR_MASK_A);
|
||||
rsxSetColorMaskMrt(gcm->context, 0);
|
||||
rsxSetDepthTestEnable(gcm->context, GCM_FALSE);
|
||||
rsxSetDepthWriteEnable(gcm->context, GCM_TRUE);
|
||||
rsxSetStencilTestEnable(gcm->context, GCM_FALSE);
|
||||
rsxSetAlphaTestEnable(gcm->context, GCM_FALSE);
|
||||
rsxSetShadeModel(gcm->context, GCM_SHADE_MODEL_SMOOTH);
|
||||
rsxSetBlendEnable(gcm->context, GCM_FALSE);
|
||||
rsxSetLogicOpEnable(gcm->context, GCM_FALSE);
|
||||
rsxSetCullFaceEnable(gcm->context, GCM_FALSE);
|
||||
rsxSetZMinMaxControl(gcm->context, GCM_FALSE, GCM_TRUE, GCM_TRUE);
|
||||
rsxSetScissor(gcm->context, 0, 0, gcm->width, gcm->height);
|
||||
rsxSetPolygonOffsetFillEnable(gcm->context, GCM_FALSE);
|
||||
for (attrib = 0; attrib < 8; attrib++)
|
||||
rsxSetViewportClip(gcm->context, attrib, gcm->width, gcm->height);
|
||||
for (attrib = 0; attrib < 16; attrib++)
|
||||
rsxBindVertexArrayAttrib(gcm->context, attrib, 0, 0,
|
||||
0, 0, GCM_VERTEX_DATA_TYPE_F32, GCM_LOCATION_RSX);
|
||||
}
|
||||
#endif
|
||||
|
||||
if (gcm->should_resize)
|
||||
rsx_update_viewport(gcm);
|
||||
|
||||
@@ -2438,6 +2705,41 @@ static bool rsx_frame(void* data, const void* frame,
|
||||
VIDEO_SCALE_H(vp.dims), vp.min, vp.max,
|
||||
vp.scale, vp.offset);
|
||||
|
||||
#ifdef __PSL1GHT__
|
||||
if (frame == RETRO_HW_FRAME_BUFFER_VALID)
|
||||
{
|
||||
if (gcm->hw_render && gcm->hw_image_valid)
|
||||
{
|
||||
rsx_texture_t texture;
|
||||
memset(&texture, 0, sizeof(texture));
|
||||
texture.tex.format = GCM_TEXTURE_FORMAT_A8R8G8B8 | GCM_TEXTURE_FORMAT_LIN;
|
||||
texture.tex.mipmap = 1;
|
||||
texture.tex.dimension = GCM_TEXTURE_DIMS_2D;
|
||||
texture.tex.remap = GCM_TEXTURE_REMAP_TYPE_REMAP << GCM_TEXTURE_REMAP_TYPE_B_SHIFT
|
||||
| GCM_TEXTURE_REMAP_TYPE_REMAP << GCM_TEXTURE_REMAP_TYPE_G_SHIFT
|
||||
| GCM_TEXTURE_REMAP_TYPE_REMAP << GCM_TEXTURE_REMAP_TYPE_R_SHIFT
|
||||
| GCM_TEXTURE_REMAP_TYPE_REMAP << GCM_TEXTURE_REMAP_TYPE_A_SHIFT
|
||||
| GCM_TEXTURE_REMAP_COLOR_A << GCM_TEXTURE_REMAP_COLOR_A_SHIFT
|
||||
| GCM_TEXTURE_REMAP_COLOR_R << GCM_TEXTURE_REMAP_COLOR_R_SHIFT
|
||||
| GCM_TEXTURE_REMAP_COLOR_G << GCM_TEXTURE_REMAP_COLOR_G_SHIFT
|
||||
| GCM_TEXTURE_REMAP_COLOR_B << GCM_TEXTURE_REMAP_COLOR_B_SHIFT;
|
||||
texture.tex.width = gcm->hw_image.width;
|
||||
texture.tex.height = gcm->hw_image.height;
|
||||
texture.tex.depth = 1;
|
||||
texture.tex.pitch = gcm->hw_image.pitch;
|
||||
texture.tex.offset = gcm->hw_image.offset;
|
||||
texture.tex.location = GCM_LOCATION_RSX;
|
||||
texture.min_filter = gcm->smooth ? GCM_TEXTURE_LINEAR : GCM_TEXTURE_NEAREST;
|
||||
texture.mag_filter = texture.min_filter;
|
||||
texture.wrap_s = GCM_TEXTURE_CLAMP_TO_EDGE;
|
||||
texture.wrap_t = GCM_TEXTURE_CLAMP_TO_EDGE;
|
||||
rsx_set_texture(gcm, &texture);
|
||||
rsx_draw_vertices(gcm);
|
||||
draw = true;
|
||||
}
|
||||
}
|
||||
else
|
||||
#endif
|
||||
if (frame && width && height)
|
||||
{
|
||||
gcm->tex_index = ((gcm->tex_index + 1) % RSX_MAX_TEXTURES);
|
||||
@@ -2789,7 +3091,11 @@ static const video_poke_interface_t rsx_poke_interface = {
|
||||
NULL, /* grab_mouse_toggle */
|
||||
NULL, /* get_current_shader */
|
||||
NULL, /* get_current_software_framebuffer */
|
||||
#ifdef __PSL1GHT__
|
||||
rsx_get_hw_render_interface,
|
||||
#else
|
||||
NULL, /* get_hw_render_interface */
|
||||
#endif
|
||||
NULL, /* set_hdr_menu_nits */
|
||||
NULL, /* set_hdr_paper_white_nits */
|
||||
NULL, /* set_hdr_expand_gamut */
|
||||
|
||||
+23
-1
@@ -40,6 +40,9 @@
|
||||
#include <formats/video_hw_frame.h>
|
||||
#include "../cores/internal_cores.h"
|
||||
#include "video_driver.h"
|
||||
#if defined(__PSL1GHT__) && defined(HAVE_GCM)
|
||||
#include <libretro_rsx.h>
|
||||
#endif
|
||||
#include "video_hdr_metadata.h"
|
||||
#include "gfx_media_display.h"
|
||||
#if defined(HAVE_X11) && defined(HAVE_XRANDR)
|
||||
@@ -1908,6 +1911,10 @@ video_driver_t *hw_render_context_driver(
|
||||
return &video_d3d9_hlsl;
|
||||
#else
|
||||
break;
|
||||
#endif
|
||||
#if defined(__PSL1GHT__) && defined(HAVE_GCM)
|
||||
case RETRO_HW_CONTEXT_RSX:
|
||||
return &video_gcm;
|
||||
#endif
|
||||
case RETRO_HW_CONTEXT_VULKAN:
|
||||
#if defined(HAVE_VULKAN)
|
||||
@@ -1964,6 +1971,10 @@ const char *hw_render_context_name(
|
||||
#ifdef HAVE_D3D12
|
||||
if (type == RETRO_HW_CONTEXT_D3D12)
|
||||
return "d3d12";
|
||||
#endif
|
||||
#if defined(__PSL1GHT__) && defined(HAVE_GCM)
|
||||
if (type == RETRO_HW_CONTEXT_RSX)
|
||||
return "rsx";
|
||||
#endif
|
||||
return "N/A";
|
||||
}
|
||||
@@ -2001,6 +2012,10 @@ static enum retro_hw_context_type hw_render_context_type(const char *s)
|
||||
#ifdef HAVE_D3D12
|
||||
if (string_is_equal(s, "d3d12"))
|
||||
return RETRO_HW_CONTEXT_D3D12;
|
||||
#endif
|
||||
#if defined(__PSL1GHT__) && defined(HAVE_GCM)
|
||||
if (string_is_equal(s, "rsx"))
|
||||
return RETRO_HW_CONTEXT_RSX;
|
||||
#endif
|
||||
return RETRO_HW_CONTEXT_NONE;
|
||||
}
|
||||
@@ -5594,13 +5609,16 @@ bool video_driver_find_driver(
|
||||
{
|
||||
switch (rdr_type)
|
||||
{
|
||||
#if defined(__PSL1GHT__) && defined(HAVE_GCM)
|
||||
case RETRO_HW_CONTEXT_RSX:
|
||||
#endif
|
||||
case RETRO_HW_CONTEXT_OPENGL_CORE:
|
||||
case RETRO_HW_CONTEXT_VULKAN:
|
||||
case RETRO_HW_CONTEXT_D3D9:
|
||||
case RETRO_HW_CONTEXT_D3D10:
|
||||
case RETRO_HW_CONTEXT_D3D11:
|
||||
case RETRO_HW_CONTEXT_D3D12:
|
||||
#if defined(HAVE_VULKAN) || defined(HAVE_D3D9) || defined(HAVE_D3D10) || defined(HAVE_D3D11) || defined(HAVE_D3D12) || defined(HAVE_OPENGL_CORE)
|
||||
#if defined(HAVE_VULKAN) || defined(HAVE_D3D9) || defined(HAVE_D3D10) || defined(HAVE_D3D11) || defined(HAVE_D3D12) || defined(HAVE_OPENGL_CORE) || (defined(__PSL1GHT__) && defined(HAVE_GCM))
|
||||
RARCH_LOG("[Video] Using HW render, %s driver forced.\n",
|
||||
rdr_context_name);
|
||||
|
||||
@@ -5722,6 +5740,10 @@ bool video_driver_is_hw_context(void)
|
||||
|
||||
bool video_driver_render_context_is_main_thread_only(void)
|
||||
{
|
||||
#if defined(__PSL1GHT__) && defined(HAVE_GCM)
|
||||
if (video_driver_st.hw_render.context_type == RETRO_HW_CONTEXT_RSX)
|
||||
return true;
|
||||
#endif
|
||||
#if TARGET_OS_IPHONE
|
||||
/* The iOS Cocoa GL/GLES backends ("gl", "glcore") render through a
|
||||
* GLKView, whose drawable and backing CAEAGLLayer may only be touched
|
||||
|
||||
@@ -0,0 +1,78 @@
|
||||
/* Copyright (C) 2010-2020 The RetroArch team
|
||||
*
|
||||
* ---------------------------------------------------------------------------------------------
|
||||
* The following license statement only applies to this libretro API header (libretro_rsx.h)
|
||||
* ---------------------------------------------------------------------------------------------
|
||||
*
|
||||
* Permission is hereby granted, free of charge,
|
||||
* to any person obtaining a copy of this software and associated documentation files (the
|
||||
* "Software"),
|
||||
* to deal in the Software without restriction, including without limitation the rights to
|
||||
* use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,
|
||||
* and to permit persons to whom the Software is furnished to do so, subject to the following
|
||||
* conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all copies or
|
||||
* substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
|
||||
* INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
||||
* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY,
|
||||
* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#ifndef LIBRETRO_RSX_H_
|
||||
#define LIBRETRO_RSX_H_
|
||||
|
||||
#include "libretro.h"
|
||||
|
||||
/* Experimental extension IDs, not upstream-assigned libretro values. */
|
||||
#define RETRO_HW_CONTEXT_RSX ((enum retro_hw_context_type)0x525358)
|
||||
#define RETRO_HW_RENDER_INTERFACE_RSX ((enum retro_hw_render_interface_type)0x525358)
|
||||
#define RETRO_HW_RENDER_INTERFACE_RSX_VERSION 1
|
||||
|
||||
/* Linear A8R8G8B8 texture in RSX local memory. The core owns the allocation
|
||||
* until context_destroy; commands and presentation use the same FIFO. */
|
||||
struct retro_rsx_image
|
||||
{
|
||||
uint32_t offset;
|
||||
uint32_t pitch;
|
||||
uint32_t width;
|
||||
uint32_t height;
|
||||
};
|
||||
|
||||
/* Query with GET_HW_RENDER_INTERFACE from context_reset, after requesting
|
||||
* RETRO_HW_CONTEXT_RSX through SET_HW_RENDER. Valid until context_destroy.
|
||||
* Both callers must submit commands on the main thread. */
|
||||
struct retro_hw_render_interface_rsx
|
||||
{
|
||||
enum retro_hw_render_interface_type interface_type;
|
||||
unsigned interface_version;
|
||||
void *handle;
|
||||
void *context;
|
||||
/* The frontend owns this mapping; only [io_used, io_size) is available
|
||||
* to the core. Do not free it or replace its command-buffer callback. */
|
||||
void *io_address;
|
||||
uint32_t io_size;
|
||||
uint32_t io_used;
|
||||
/* Publish an image before video_refresh(RETRO_HW_FRAME_BUFFER_VALID).
|
||||
* NULL releases the cached image. No allocation or CPU wait is performed. */
|
||||
bool (*set_image)(void *handle, const struct retro_rsx_image *image);
|
||||
};
|
||||
|
||||
/* Request context version 2 for nonblocking retirement of local allocations.
|
||||
* Version 1 clients continue receiving the version 1 interface. */
|
||||
#define RETRO_HW_RENDER_INTERFACE_RSX_V2_VERSION 2
|
||||
struct retro_hw_render_interface_rsx_v2
|
||||
{
|
||||
struct retro_hw_render_interface_rsx base;
|
||||
/* Transfers ownership of an rsxMemalign allocation to the frontend.
|
||||
* It is freed after submitted commands finish. NULL is accepted.
|
||||
* Label 199 belongs to the frontend. Returns false if the queue is full. */
|
||||
bool (*retire_memory)(void *handle, void *memory);
|
||||
};
|
||||
|
||||
#endif /* LIBRETRO_RSX_H_ */
|
||||
@@ -71,6 +71,9 @@
|
||||
#include <encodings/utf.h>
|
||||
|
||||
#include <libretro.h>
|
||||
#if defined(__PSL1GHT__) && defined(HAVE_GCM)
|
||||
#include <libretro_rsx.h>
|
||||
#endif
|
||||
#ifdef HAVE_RMP4
|
||||
#include <formats/rh264.h>
|
||||
#endif
|
||||
@@ -1222,6 +1225,12 @@ static bool dynamic_verify_hw_context(
|
||||
size_t len = strlen(video_ident);
|
||||
switch (type)
|
||||
{
|
||||
#if defined(__PSL1GHT__) && defined(HAVE_GCM)
|
||||
case RETRO_HW_CONTEXT_RSX:
|
||||
if (!(len == 3 && memcmp(video_ident, "rsx", 3) == 0))
|
||||
return false;
|
||||
break;
|
||||
#endif
|
||||
case RETRO_HW_CONTEXT_VULKAN:
|
||||
if (!(len == 6 && memcmp(video_ident, "vulkan", 6) == 0))
|
||||
return false;
|
||||
@@ -1303,6 +1312,14 @@ static bool dynamic_request_hw_context(enum retro_hw_context_type type,
|
||||
RARCH_LOG("[HW] Requesting no HW context.\n");
|
||||
break;
|
||||
|
||||
#if defined(__PSL1GHT__) && defined(HAVE_GCM)
|
||||
case RETRO_HW_CONTEXT_RSX:
|
||||
if (major > 2 || minor != 0)
|
||||
return false;
|
||||
RARCH_LOG("[HW] Requesting RSX context.\n");
|
||||
break;
|
||||
#endif
|
||||
|
||||
case RETRO_HW_CONTEXT_VULKAN:
|
||||
#ifdef HAVE_VULKAN
|
||||
RARCH_LOG("[HW] Requesting Vulkan context.\n");
|
||||
|
||||
@@ -26,6 +26,7 @@
|
||||
* vertices land where the RSX is pointed at, inside their buffer,
|
||||
* and vertices queued for the RSX are not written over by the next
|
||||
* draw, message or frame.
|
||||
* - font_batches: large batches, independent font cursors and GPU fences.
|
||||
* - native_menu_frame, menu_dupe_frame: a menu with no new core
|
||||
* frame is presented, over the last core frame if there is one.
|
||||
*
|
||||
@@ -131,6 +132,7 @@ s32 rsxAddressToOffset(const void *ptr, u32 *offset)
|
||||
static gcmContextData fake_context;
|
||||
static void *fake_host_addr;
|
||||
static u32 fake_labels[256];
|
||||
static bool fake_defer_backend;
|
||||
static u8 fake_ucode[64];
|
||||
static rsxProgramConst fake_const;
|
||||
static rsxProgramAttrib fake_attrib;
|
||||
@@ -147,8 +149,9 @@ s32 rsxInit(gcmContextData **context, u32 cmdSize, u32 ioSize,
|
||||
}
|
||||
|
||||
void rsxFinish(gcmContextData *context, u32 ref_value) { rsx_finish_calls++; }
|
||||
void rsxSetWaitForIdle(gcmContextData *context) { }
|
||||
void rsxSetWriteBackendLabel(gcmContextData *context, u8 index, u32 value)
|
||||
{ fake_labels[index] = value; }
|
||||
{ if (!fake_defer_backend) fake_labels[index] = value; }
|
||||
u32 *gcmGetLabelAddress(const u8 index) { return &fake_labels[index]; }
|
||||
u32 gcmGetFlipStatus(void) { return 0; }
|
||||
void gcmResetFlipStatus(void) { }
|
||||
@@ -177,6 +180,9 @@ void rsxBindVertexArrayAttrib(gcmContextData *c, u8 attr, u16 frequency,
|
||||
u32 offset, u8 stride, u8 elems, u8 dtype, u8 location) { }
|
||||
void rsxClearSurface(gcmContextData *c, u32 clear_mask) { }
|
||||
static unsigned rsx_draw_calls;
|
||||
static unsigned rsx_vertex_invalidations;
|
||||
void rsxInvalidateVertexCache(gcmContextData *context)
|
||||
{ rsx_vertex_invalidations++; }
|
||||
void rsxDrawVertexArray(gcmContextData *c, u32 type, u32 start, u32 count)
|
||||
{ rsx_draw_calls++; }
|
||||
void rsxFlushBuffer(gcmContextData *c) { }
|
||||
@@ -200,6 +206,12 @@ void rsxSetColorMask(gcmContextData *c, u32 mask) { }
|
||||
void rsxSetColorMaskMrt(gcmContextData *c, u32 mask) { }
|
||||
void rsxSetDepthFunc(gcmContextData *c, u32 func) { }
|
||||
void rsxSetDepthTestEnable(gcmContextData *c, u32 enable) { }
|
||||
void rsxSetDepthWriteEnable(gcmContextData *c, u32 enable) { }
|
||||
void rsxSetStencilTestEnable(gcmContextData *c, u32 enable) { }
|
||||
void rsxSetLogicOpEnable(gcmContextData *c, u32 enable) { }
|
||||
void rsxSetCullFaceEnable(gcmContextData *c, u32 enable) { }
|
||||
void rsxSetPolygonOffsetFillEnable(gcmContextData *c, u32 enable) { }
|
||||
void rsxSetShadeModel(gcmContextData *c, u32 mode) { }
|
||||
void rsxSetScissor(gcmContextData *c, u16 x, u16 y, u16 w, u16 h) { }
|
||||
void rsxSetSurface(gcmContextData *c, const gcmSurface *surface) { }
|
||||
void rsxSetUserClipPlaneControl(gcmContextData *c, u32 plane0,
|
||||
@@ -844,6 +856,87 @@ static void test_font_queue(void)
|
||||
printf("font_queue: ok\n");
|
||||
}
|
||||
|
||||
/* Ozone batches may exceed the initial font buffer. */
|
||||
static void test_font_batches(void)
|
||||
{
|
||||
video_coords_t coords;
|
||||
rsx_t *rsx = driver_up();
|
||||
rsx_font_t *font = (rsx_font_t*)rsx_font_init(rsx, NULL, 12.0f, false);
|
||||
rsx_font_t *other = (rsx_font_t*)rsx_font_init(rsx, NULL, 12.0f, false);
|
||||
unsigned count = 9384;
|
||||
float *data = (float*)malloc(count * 8 * sizeof(float));
|
||||
rsx_vertex_t *queued[RSX_FONT_VERTEX_PAGES];
|
||||
unsigned i, draws, live, finishes = rsx_finish_calls;
|
||||
unsigned first_draw = rsx_draw_calls;
|
||||
unsigned invalidations = rsx_vertex_invalidations;
|
||||
CHECK(font && other && data, "font_batches: allocation");
|
||||
if (!font || !other || !data)
|
||||
exit(1);
|
||||
for (i = 0; i < count * 8; i++)
|
||||
data[i] = 1.0f;
|
||||
memset(&coords, 0, sizeof(coords));
|
||||
coords.vertex = data;
|
||||
coords.tex_coord = data + count * 2;
|
||||
coords.color = data + count * 4;
|
||||
coords.vertices = 6;
|
||||
rsx_font_draw_vertices(rsx, font, &coords);
|
||||
rsx_font_draw_vertices(rsx, other, &coords);
|
||||
CHECK(other->vertex_pages[0].used == 6,
|
||||
"font_batches: font cursors shared");
|
||||
rsx_font_draw_vertices(rsx, font, &coords);
|
||||
CHECK(font->vertex_pages[0].used == 12,
|
||||
"font_batches: other font moved cursor");
|
||||
|
||||
fake_defer_backend = true;
|
||||
coords.vertices = count;
|
||||
draws = rsx_draw_calls;
|
||||
live = rsx_live();
|
||||
rsx_fail_at = rsx_alloc_calls + 1;
|
||||
rsx_font_draw_vertices(rsx, font, &coords);
|
||||
CHECK(rsx_draw_calls == draws && rsx_live() == live,
|
||||
"font_batches: allocation failure submitted a draw");
|
||||
CHECK(font->vertices[0].r == 1.0f,
|
||||
"font_batches: allocation failure overwrote queued text");
|
||||
rsx_fail_at = 0;
|
||||
fake_labels[RSX_FONT_VERTEX_LABEL] = rsx_font_vertex_serial;
|
||||
for (i = 0; i < RSX_FONT_VERTEX_PAGES; i++)
|
||||
{
|
||||
data[count * 4] = (float)(i + 2);
|
||||
rsx_font_draw_vertices(rsx, font, &coords);
|
||||
queued[i] = font->vertices;
|
||||
CHECK(font->vertex_pages[font->vertex_page].capacity >= count,
|
||||
"font_batches: oversized batch outside allocation");
|
||||
CHECK(font->vertices[count - 1].a == 1.0f,
|
||||
"font_batches: oversized batch truncated");
|
||||
}
|
||||
draws = rsx_draw_calls;
|
||||
rsx_font_draw_vertices(rsx, font, &coords);
|
||||
CHECK(rsx_draw_calls == draws,
|
||||
"font_batches: reused a buffer still on the GPU");
|
||||
for (i = 0; i < RSX_FONT_VERTEX_PAGES; i++)
|
||||
CHECK(queued[i][0].r == (float)(i + 2),
|
||||
"font_batches: pending page %u overwritten", i);
|
||||
fake_labels[RSX_FONT_VERTEX_LABEL] = rsx_font_vertex_serial;
|
||||
rsx_font_draw_vertices(rsx, font, &coords);
|
||||
CHECK(rsx_draw_calls == draws + 1,
|
||||
"font_batches: completed pages not reused");
|
||||
draws = rsx_draw_calls;
|
||||
coords.vertices = (unsigned)-1;
|
||||
rsx_font_draw_vertices(rsx, font, &coords);
|
||||
CHECK(rsx_draw_calls == draws, "font_batches: size overflow accepted");
|
||||
CHECK(rsx_finish_calls == finishes, "font_batches: waits for the GPU");
|
||||
CHECK(rsx_vertex_invalidations - invalidations
|
||||
== rsx_draw_calls - first_draw,
|
||||
"font_batches: vertex cache not invalidated between batches");
|
||||
fake_defer_backend = false;
|
||||
fake_labels[RSX_FONT_VERTEX_LABEL] = rsx_font_vertex_serial;
|
||||
free(data);
|
||||
rsx_font_free(other, false);
|
||||
rsx_font_free(font, false);
|
||||
driver_down(rsx);
|
||||
printf("font_batches: ok\n");
|
||||
}
|
||||
|
||||
/* A duped core frame is drawn again behind the menu, as the surface
|
||||
* it was drawn to has been cleared */
|
||||
static void test_menu_dupe_frame(void)
|
||||
@@ -882,6 +975,110 @@ static void test_menu_dupe_frame(void)
|
||||
printf("menu_dupe_frame: ok\n");
|
||||
}
|
||||
|
||||
static void test_hw_interface(void)
|
||||
{
|
||||
const struct retro_hw_render_interface *base = NULL;
|
||||
const struct retro_hw_render_interface_rsx *iface;
|
||||
struct retro_rsx_image image;
|
||||
video_frame_info_t info;
|
||||
rsx_t *rsx;
|
||||
unsigned draws, allocations, finishes;
|
||||
memset(&info, 0, sizeof(info));
|
||||
CHECK(!rsx_get_hw_render_interface(NULL, &base),
|
||||
"hw_interface: no interface without a driver");
|
||||
fake_hwr.context_type = RETRO_HW_CONTEXT_NONE;
|
||||
rsx = driver_up();
|
||||
CHECK(!rsx_get_hw_render_interface(rsx, &base),
|
||||
"hw_interface: software cores keep the software path");
|
||||
driver_down(rsx);
|
||||
fake_hwr.context_type = RETRO_HW_CONTEXT_RSX;
|
||||
rsx = driver_up();
|
||||
CHECK(rsx_get_hw_render_interface(rsx, &base),
|
||||
"hw_interface: negotiated RSX interface available");
|
||||
iface = (const struct retro_hw_render_interface_rsx*)base;
|
||||
CHECK(iface->interface_type == RETRO_HW_RENDER_INTERFACE_RSX
|
||||
&& iface->interface_version == RETRO_HW_RENDER_INTERFACE_RSX_VERSION,
|
||||
"hw_interface: type and version advertised");
|
||||
CHECK(iface->context == rsx->context && iface->io_address == fake_host_addr,
|
||||
"hw_interface: frontend owns context and mapping");
|
||||
CHECK(iface->io_size == HOST_SIZE && iface->io_used >= CB_SIZE
|
||||
&& iface->io_used < iface->io_size,
|
||||
"hw_interface: host mapping excludes command buffer");
|
||||
rsx->video_info.is_threaded = true;
|
||||
CHECK(!rsx_get_hw_render_interface(rsx, &base),
|
||||
"hw_interface: threaded access refused");
|
||||
image.offset = 0x10000;
|
||||
image.pitch = 512 * 4;
|
||||
image.width = 480;
|
||||
image.height = 272;
|
||||
CHECK(!iface->set_image(iface->handle, &image),
|
||||
"hw_interface: threaded image submission refused");
|
||||
rsx->video_info.is_threaded = false;
|
||||
CHECK(iface->set_image(iface->handle, &image),
|
||||
"hw_interface: core-owned texture accepted");
|
||||
allocations = rsx_alloc_calls;
|
||||
finishes = rsx_finish_calls;
|
||||
draws = rsx_draw_calls;
|
||||
rsx_frame(rsx, RETRO_HW_FRAME_BUFFER_VALID, VIDEO_SCALE_PACK(480, 272),
|
||||
0, 0, NULL, &info);
|
||||
CHECK(rsx_draw_calls == draws + 1 && rsx_alloc_calls == allocations,
|
||||
"hw_interface: GPU image displayed without allocation or CPU upload");
|
||||
CHECK(rsx_finish_calls == finishes,
|
||||
"hw_interface: handoff does not wait for the GPU");
|
||||
image.pitch = 1;
|
||||
CHECK(!iface->set_image(iface->handle, &image),
|
||||
"hw_interface: invalid pitch rejected");
|
||||
draws = rsx_draw_calls;
|
||||
rsx_frame(rsx, RETRO_HW_FRAME_BUFFER_VALID, VIDEO_SCALE_PACK(480, 272),
|
||||
1, 0, NULL, &info);
|
||||
CHECK(rsx_draw_calls == draws, "hw_interface: rejected image not reused");
|
||||
image.pitch = 512 * 4;
|
||||
image.offset = UINT32_MAX - 128;
|
||||
CHECK(!iface->set_image(iface->handle, &image),
|
||||
"hw_interface: overflowing local-memory range rejected");
|
||||
CHECK(iface->set_image(iface->handle, NULL),
|
||||
"hw_interface: cached image released");
|
||||
driver_down(rsx);
|
||||
fake_hwr.context_type = RETRO_HW_CONTEXT_NONE;
|
||||
printf("hw_interface: ok\n");
|
||||
}
|
||||
|
||||
static void test_hw_retirement(void)
|
||||
{
|
||||
const struct retro_hw_render_interface *base = NULL;
|
||||
const struct retro_hw_render_interface_rsx_v2 *iface;
|
||||
rsx_t *rsx;
|
||||
void *memory;
|
||||
unsigned live, finishes;
|
||||
fake_hwr.context_type = RETRO_HW_CONTEXT_RSX;
|
||||
fake_hwr.version_major = 2;
|
||||
rsx = driver_up();
|
||||
CHECK(rsx_get_hw_render_interface(rsx, &base), "hw_retirement: v2 available");
|
||||
iface = (const struct retro_hw_render_interface_rsx_v2*)base;
|
||||
CHECK(iface->base.interface_version == 2 && iface->retire_memory,
|
||||
"hw_retirement: retirement callback advertised");
|
||||
memory = rsxMemalign(128, 128);
|
||||
live = rsx_live();
|
||||
finishes = rsx_finish_calls;
|
||||
fake_defer_backend = true;
|
||||
CHECK(iface->retire_memory(iface->base.handle, memory),
|
||||
"hw_retirement: allocation ownership transferred");
|
||||
rsx_collect_retired_memory();
|
||||
CHECK(rsx_live() == live && rsx_finish_calls == finishes,
|
||||
"hw_retirement: pending GPU memory preserved without waiting");
|
||||
free(rsx->white_texture);
|
||||
free(rsx);
|
||||
CHECK(rsx_retired_memory_count == 1, "hw_retirement: survives driver teardown");
|
||||
fake_labels[RSX_RETIRED_MEMORY_LABEL] = rsx_retired_memory_serial;
|
||||
rsx_collect_retired_memory();
|
||||
CHECK(rsx_retired_memory_count == 0, "hw_retirement: completed allocation freed");
|
||||
rsx_release_all();
|
||||
fake_defer_backend = false;
|
||||
fake_hwr.context_type = RETRO_HW_CONTEXT_NONE;
|
||||
fake_hwr.version_major = 0;
|
||||
printf("hw_retirement: ok\n");
|
||||
}
|
||||
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
static const struct
|
||||
@@ -889,6 +1086,8 @@ int main(int argc, char **argv)
|
||||
const char *name;
|
||||
void (*run)(void);
|
||||
} tests[] = {
|
||||
{ "hw_interface", test_hw_interface },
|
||||
{ "hw_retirement", test_hw_retirement },
|
||||
{ "texture_grow", test_texture_grow },
|
||||
{ "texture_fail", test_texture_fail },
|
||||
{ "frame_fail", test_frame_fail },
|
||||
@@ -900,6 +1099,7 @@ int main(int argc, char **argv)
|
||||
{ "native_menu_frame", test_native_menu_frame },
|
||||
{ "menu_frame_vertices", test_menu_frame_vertices },
|
||||
{ "font_queue", test_font_queue },
|
||||
{ "font_batches", test_font_batches },
|
||||
{ "menu_dupe_frame", test_menu_dupe_frame },
|
||||
};
|
||||
unsigned i;
|
||||
|
||||
@@ -95,6 +95,7 @@ void rsxBindVertexArrayAttrib(gcmContextData *context, u8 attr,
|
||||
u16 frequency, u32 offset, u8 stride, u8 elems, u8 dtype,
|
||||
u8 location);
|
||||
void rsxClearSurface(gcmContextData *context, u32 clear_mask);
|
||||
void rsxInvalidateVertexCache(gcmContextData *context);
|
||||
void rsxDrawVertexArray(gcmContextData *context, u32 type, u32 start,
|
||||
u32 count);
|
||||
void rsxFinish(gcmContextData *context, u32 ref_value);
|
||||
@@ -120,6 +121,13 @@ void rsxSetColorMask(gcmContextData *context, u32 mask);
|
||||
void rsxSetColorMaskMrt(gcmContextData *context, u32 mask);
|
||||
void rsxSetDepthFunc(gcmContextData *context, u32 func);
|
||||
void rsxSetDepthTestEnable(gcmContextData *context, u32 enable);
|
||||
#define GCM_SHADE_MODEL_SMOOTH 0x1d01
|
||||
void rsxSetDepthWriteEnable(gcmContextData *context, u32 enable);
|
||||
void rsxSetStencilTestEnable(gcmContextData *context, u32 enable);
|
||||
void rsxSetLogicOpEnable(gcmContextData *context, u32 enable);
|
||||
void rsxSetCullFaceEnable(gcmContextData *context, u32 enable);
|
||||
void rsxSetPolygonOffsetFillEnable(gcmContextData *context, u32 enable);
|
||||
void rsxSetShadeModel(gcmContextData *context, u32 mode);
|
||||
void rsxSetScissor(gcmContextData *context, u16 x, u16 y, u16 w, u16 h);
|
||||
void rsxSetSurface(gcmContextData *context, const gcmSurface *surface);
|
||||
void rsxSetUserClipPlaneControl(gcmContextData *context, u32 plane0,
|
||||
@@ -133,6 +141,7 @@ void rsxSetViewport(gcmContextData *context, u16 x, u16 y, u16 width,
|
||||
void rsxSetViewportClip(gcmContextData *context, u8 sel, u16 width,
|
||||
u16 height);
|
||||
void rsxSetWaitLabel(gcmContextData *context, u8 index, u32 value);
|
||||
void rsxSetWaitForIdle(gcmContextData *context);
|
||||
void rsxSetWriteBackendLabel(gcmContextData *context, u8 index,
|
||||
u32 value);
|
||||
void rsxSetZMinMaxControl(gcmContextData *context, u8 cullNearFar,
|
||||
|
||||
Reference in new issue
Block a user