mirror of
https://gitea.murdle.top/murdle/mc-lce.git
synced 2026-03-19 05:29:00 +02:00
265 lines
14 KiB
C
265 lines
14 KiB
C
// gdraw_psp2.h - author: Fabian Giesen - copyright 2014 RAD Game Tools
|
|
//
|
|
// Interface for creating a PSP2 GDraw driver.
|
|
|
|
#include "gdraw.h"
|
|
|
|
#define IDOC
|
|
//idoc(parent,GDraw_psp2)
|
|
|
|
// Size and alignment requirements of GDraw context memory.
|
|
#define GDRAW_PSP2_CONTEXT_MEM_SIZE (16*1024)
|
|
|
|
// Alignment requirements for different resource types (in bytes)
|
|
#define GDRAW_PSP2_TEXTURE_ALIGNMENT 16
|
|
#define GDRAW_PSP2_VERTEXBUFFER_ALIGNMENT 16
|
|
|
|
typedef enum gdraw_psp2_resourcetype
|
|
{
|
|
GDRAW_PSP2_RESOURCE_texture,
|
|
GDRAW_PSP2_RESOURCE_vertexbuffer,
|
|
|
|
GDRAW_PSP2_RESOURCE__count,
|
|
} gdraw_psp2_resourcetype;
|
|
|
|
typedef struct
|
|
{
|
|
U32 allocs_attempted; // number of allocations attempted from the staging buffer
|
|
U32 allocs_succeeded; // number of allocations that succeeded
|
|
U32 bytes_attempted; // number of bytes attempted to allocate
|
|
U32 bytes_succeeded; // number of bytes successfully allocated
|
|
U32 largest_bytes_attempted; // number of bytes in largest attempted alloc
|
|
U32 largest_bytes_succeeded; // number of bytes in lagrest successful alloc
|
|
} gdraw_psp2_dynamic_stats;
|
|
|
|
typedef struct
|
|
{
|
|
void *start; // pointer to the start of the buffer
|
|
U32 size_in_bytes; // size of the buffer in bytes
|
|
U64 sync; // used internally by GDraw for synchronization.
|
|
|
|
gdraw_psp2_dynamic_stats stats; // stats on buffer usage - these are for your benefit!
|
|
} gdraw_psp2_dynamic_buffer;
|
|
|
|
IDOC extern void gdraw_psp2_InitDynamicBuffer(gdraw_psp2_dynamic_buffer *buffer, void *ptr, U32 num_bytes);
|
|
/* Initializes a GDraw dynamic buffer struct.
|
|
|
|
The "dynamic buffer" is where GDraw stores all transient data for a scene - dynamic
|
|
vertex and index data, uniform buffers and the like. We wrap them in a struct
|
|
so we can handle synchronization with the GPU.
|
|
|
|
"ptr" should point to non-cached, GPU-mapped readable memory. "num_bytes" is the size of
|
|
the buffer in bytes. */
|
|
|
|
IDOC extern void gdraw_psp2_WaitForDynamicBufferIdle(gdraw_psp2_dynamic_buffer *buffer);
|
|
/* Waits until a GDraw dynamic buffer is idle, i.e. not being used by the
|
|
GPU anymore. You need to call this if you intend to free the allocated storage. */
|
|
|
|
IDOC extern int gdraw_psp2_SetResourceMemory(gdraw_psp2_resourcetype type, S32 num_handles, void *ptr, S32 num_bytes);
|
|
/* Sets up the resource pools that GDraw uses for its video memory management.
|
|
|
|
It sets both the number of handles and the address and size of memory to use.
|
|
GDraw keeps track of allocations in each pool, and will free old resources in
|
|
a LRU manner to make space if one of the limits is about to be exceeded. It will
|
|
also automatically defragment memory if necessary to fulfill an allocation
|
|
request.
|
|
|
|
"ptr" points to the address of the resource pool. This memory needs to be
|
|
mapped to the GPU and *writeable*. If it isn't, the GPU will crash during
|
|
either this function or CreateContext!
|
|
|
|
Pass in NULL for "ptr" and zero "num_bytes" to free the memory allocated to
|
|
a specific pool.
|
|
|
|
GDraw can run into cases where resource memory gets fragmented; we defragment
|
|
automatically in that case. However, to make this work, GDraw on PSP2 needs
|
|
resource pool memory equivalent to *twice* the largest working set in any
|
|
scene. So for example, if you use 10MB worth of textures, GDraw needs at least
|
|
a 20MB texture pool! On other platforms, we can avoid this extra cost by
|
|
draining the GPU pipeline in the middle of a frame in certain rare cases, but
|
|
doing so on PSP2 would mean not supporting deferred contexts.
|
|
|
|
You need to set up all of the resource pools before you can start rendering.
|
|
If you modify this at runtime, you need to call IggyPlayerFlushAll on all
|
|
active Iggys (if any) since this call invalidates all resource handles they
|
|
currently hold.
|
|
|
|
Resource pool memory has certain alignment requirements - see the #defines
|
|
above. If you pass in an unaligned pointer, GDraw will automatically clip off
|
|
some bytes at the front to make the buffer aligned - in other words, you get
|
|
somewhat less usable bytes, but it should work fine.
|
|
|
|
If any Iggy draw calls are in flight, this call will block waiting for
|
|
those calls to finish (i.e. for the resource memory to become
|
|
unused).
|
|
*/
|
|
|
|
IDOC extern void gdraw_psp2_ResetAllResourceMemory();
|
|
/* Frees all resource pools managed by GDraw.
|
|
|
|
Use this as a quick way of freeing (nearly) all memory allocated by GDraw
|
|
without shutting it down completely. For example, you might want to use this
|
|
to quickly flush all memory allocated by GDraw when transitioning between the
|
|
main menu and the game proper. Like with SetResourceMemory, you need to call
|
|
IggyPlayerFlushAll on all currently active Iggy players if you do this - although
|
|
we recommend that you only use this function when there aren't any. */
|
|
|
|
IDOC extern GDrawFunctions * gdraw_psp2_CreateContext(SceGxmShaderPatcher *shader_patcher, void *context_mem, volatile U32 *notification, SceGxmOutputRegisterFormat reg_format);
|
|
/* Creates a GDraw context for rendering using GXM. You need to pass in a pointer to
|
|
the shader patcher to use, a pointer to "context memory" which holds a few persistent
|
|
resources shared by all Iggys (it needs to hold GDRAW_PSP2_CONTEXT_MEM_SIZE bytes
|
|
and must be mapped to be GPU readable), and a pointer to the notificaiton to use for
|
|
GDraw sync.
|
|
|
|
"reg_format" specifies the output register format to specify when creating
|
|
GDraw's fragment shaders. This should match your color surface. Typical choices
|
|
are:
|
|
- SCE_GXM_OUTPUT_REGISTER_FORMAT_UCHAR4 (32-bit output register size in color surface)
|
|
- SCE_GXM_OUTPUT_REGISTER_FORMAT_HALF4 (64-bit output register size in color surface)
|
|
|
|
There can only be one GDraw context active at any one time. The shader_patcher must
|
|
be valid for as long as a GDraw context is alive.
|
|
|
|
If initialization fails for some reason (the main reason would be an out of memory condition),
|
|
NULL is returned. Otherwise, you can pass the return value to IggySetGDraw. */
|
|
|
|
IDOC extern void gdraw_psp2_DestroyContext(void);
|
|
/* Destroys the current GDraw context, if any.
|
|
|
|
If any Iggy draw calls are in flight, this call will block waiting for
|
|
those calls to finish (i.e. for the resource memory to become
|
|
unused).
|
|
*/
|
|
|
|
IDOC extern void gdraw_psp2_Begin(SceGxmContext *context, const SceGxmColorSurface *color, const SceGxmDepthStencilSurface *depth,
|
|
gdraw_psp2_dynamic_buffer *dynamic_buffer);
|
|
/* This sets the SceGxmContext that GDraw writes its commands to. It also specifies
|
|
the dynamic buffer to use. Any GDraw / Iggy rendering calls outside a
|
|
Begin / End bracket are an error and will be treated as such. The GXM context
|
|
and dynamic buffer must be live during the entire Begin / End bracket.
|
|
|
|
NOTE: If you are passing in a deferred context, see important notes below!
|
|
|
|
GDraw uses the color and depth surfaces for parameter validation. Make sure to
|
|
pass in the same values you passed in to sceGxmBeginScene. Also, inside a given
|
|
scene, you may have only *one* $gdraw_psp2_Begin / $gdraw_psp2_End pair.
|
|
|
|
GDraw maintains a persistent resource cache shared across all Iggys. Because of this,
|
|
it is *vital* that all command lists generated from GDraw be executed in the order
|
|
they were generated, or the resource pools might get corrupted.
|
|
|
|
If the dynamic buffer is of insufficient size, GDraw will not be able to allocate dynamic
|
|
vertex data or upload new texture/vertex buffer data during some frames, resulting in
|
|
glitching! (When this happens, it will be reported as a warning, so make sure to install
|
|
a warning callback).
|
|
|
|
You should use multiple dynamic buffers (at least double-buffer it); otherwise,
|
|
GDraw needs to stall every frame to wait for the GPU to process the previous one.
|
|
|
|
GDraw starts no scenes of its own; you must call BeginScene before you issue
|
|
gdraw_psp2_Begin.
|
|
|
|
If you are a using a deferred context:
|
|
--------------------------------------
|
|
|
|
It's allowed to pass in a deferred context as "context". You may perform Iggy
|
|
rendering on a separate thread. However, because there is only a single global
|
|
resource pool that is modified directly by GDraw, rendering is *not* thread-safe;
|
|
that is, you may do Iggy rendering on any thread, but only a single thread may
|
|
be inside a GDraw Begin / End bracket at any given time.
|
|
|
|
Furthermore, if you use a deferred context, you must use (and execute!) the
|
|
resulting command list and end the containing scene *before* you call
|
|
$gdraw_psp2_Begin again. That is, usage must look like this:
|
|
|
|
Main thread: | Other thread:
|
|
<other work> | gdraw_psp2_Begin(deferred_ctx, ...)
|
|
| <render Iggys>
|
|
| gdraw_psp2_End(deferred_ctx, ...)
|
|
| ...
|
|
| sceGxmEndCommandList(deferred_ctx, &cmd_list)
|
|
|
|
|
sceGxmBeginScene(...) | <other work>
|
|
sceGxmExecuteCommandList(..., cmd_list) |
|
|
sceGxmEndScene() |
|
|
|
|
The second thread may *not* start another $gdraw_psp2_Begin before the main thread
|
|
calls sceGxmEndScene().
|
|
|
|
This is inconvenient, but unfortunately required by our resource management: every
|
|
GDraw Begin / End Bracket may end up having to wait for the GPU to finish work done
|
|
during a previous bracket, and this only works if the corresponding jobs have been
|
|
submitted to the GPU by the point $gdraw_psp2_Begin is called!
|
|
*/
|
|
|
|
IDOC extern SceGxmNotification gdraw_psp2_End();
|
|
/* This marks the end of GDraw rendering for a frame. It also triggers end-of-frame processing,
|
|
which is important for GDraw's internal resource management. GDraw will not touch the GXM context
|
|
or staging buffer after this call, so you are free to append other rendering commands after
|
|
this call returns.
|
|
|
|
This function will also update the "stats" field in the dynamic buffer you passed
|
|
to "Begin".
|
|
|
|
You are *required* to pass the returned SceGxmNotification as your "fragment notification"
|
|
when calling sceGxmEndScene. This is necessary to make GDraw's resource management work! */
|
|
|
|
IDOC extern void gdraw_psp2_SetTileOrigin(S32 x, S32 y);
|
|
/* This sets the x/y position of the output location of the top-left pixel of the current
|
|
tile. Iggy has support for manual splitting of rendering into multiple tiles; PSP2 is
|
|
already a tiled renderer that handles all this in hardware, so in practice
|
|
you will probably always pass (0,0) here.
|
|
|
|
You should call this inside a gdraw_psp2_Begin / gdraw_psp2_End bracket, before
|
|
any Iggy / GDraw rendering takes place. */
|
|
|
|
IDOC extern void gdraw_psp2_ClearBeforeNextRender(const F32 clear_color_rgba[4]);
|
|
/* You often want to clear the render target before you start Iggy rendering.
|
|
|
|
This is a convenience function, if you don't want to do the clear yourself.
|
|
Iggy always clears the depth/stencil buffers when it starts rendering; if you
|
|
call this function first, it will also clear the color surface to the
|
|
specified color during that initial clear. If this function is not called
|
|
before rendering, GDraw will leave the contents of the color surface alone.
|
|
|
|
This function does not do any rendering; it just sets some internal state
|
|
that GDraw processes when it starts rendering. That state gets reset for every
|
|
call to IggyPlayerDraw or IggyPlayerDrawTile. */
|
|
|
|
IDOC extern void RADLINK gdraw_psp2_CalculateCustomDraw_4J(IggyCustomDrawCallbackRegion *region, float matrix[16]);
|
|
IDOC extern void RADLINK gdraw_psp2_BeginCustomDraw(IggyCustomDrawCallbackRegion *region, float matrix[16]);
|
|
/* Call at the beginning of Iggy custom draw callback to clear any odd render states GDraw has
|
|
set, and to get the current 2D object-to-world transformation. */
|
|
|
|
IDOC extern void RADLINK gdraw_psp2_EndCustomDraw(IggyCustomDrawCallbackRegion *region);
|
|
/* Call at the end of Iggy custom draw callback so GDraw can restore its render states. */
|
|
|
|
IDOC extern GDrawTexture *gdraw_psp2_WrappedTextureCreate(SceGxmTexture *tex);
|
|
/* Create a wrapped texture from a GXM texture.
|
|
A wrapped texture can be used to let Iggy draw using the contents of a texture
|
|
you create and manage on your own. For example, you might render to this texture,
|
|
or stream video into it. Wrapped textures take up a handle. They will never be
|
|
freed or otherwise modified by GDraw; nor will GDraw change any reference counts.
|
|
All this is up to the application.
|
|
GDraw makes a copy of the contents of the sceGxmTexture (the contents of the struct
|
|
that is, not the data it points to). If you later modify the fields of "tex", you
|
|
need to call $gdraw_psp2_WrappedTextureChange.
|
|
*/
|
|
|
|
IDOC extern void gdraw_psp2_WrappedTextureChange(GDrawTexture *handle, SceGxmTexture *tex);
|
|
/* Switch an existing GDrawTexture * that represents a wrapped texture to use
|
|
a new underlying GXM texture. For example, you might internally double-buffer
|
|
a dynamically updated texture. As above, GDraw will leave this texture alone
|
|
and not touch any reference counts. */
|
|
|
|
IDOC extern void gdraw_psp2_WrappedTextureDestroy(GDrawTexture *handle);
|
|
/* Destroys the GDraw wrapper for a wrapped texture object. This will free up
|
|
a GDraw texture handle but not release the associated GXM texture; that is
|
|
up to you. */
|
|
|
|
IDOC extern GDrawTexture * RADLINK gdraw_psp2_MakeTextureFromResource(U8 *file_in_memory, S32 length, IggyFileTexturePSP2 *tex);
|
|
/* Sets up a texture loaded from a .psp2.iggytex file. */
|
|
|
|
extern void RADLINK gdraw_psp2_DestroyTextureFromResource(GDrawTexture *tex);
|
|
|