193 lines
15 KiB
C
193 lines
15 KiB
C
/*
|
|
*
|
|
* Singe 3
|
|
* Copyright (C) 2006-2026 Scott Duensing <scott@kangaroopunch.com>
|
|
*
|
|
* This program is free software; you can redistribute it and/or
|
|
* modify it under the terms of the GNU General Public License
|
|
* as published by the Free Software Foundation; either version 3
|
|
* of the License, or (at your option) any later version.
|
|
*
|
|
* This program is distributed in the hope that it will be useful,
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
* GNU General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU General Public License
|
|
* along with this program; if not, write to the Free Software
|
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
|
|
* 02110-1301, USA.
|
|
*
|
|
*/
|
|
|
|
#ifndef RENDER_H
|
|
#define RENDER_H
|
|
|
|
#include <stdbool.h>
|
|
#include <stdint.h>
|
|
#include <SDL3/SDL.h>
|
|
|
|
#ifdef __cplusplus
|
|
extern "C" {
|
|
#endif
|
|
|
|
|
|
// The rendering backend, behind one table of function pointers.
|
|
//
|
|
// SDL_GPU has Vulkan, Direct3D 12 and Metal and no OpenGL of any kind, which leaves the cheap
|
|
// handhelds and the Pi with 2D only: they have GLES and nothing else. Rather than grow a second
|
|
// renderer beside scene.c and guiRender.cpp -- two descriptions of the same picture, drifting apart
|
|
// -- the subset of SDL_GPU those files actually use is virtualised here and implemented twice. It
|
|
// is 45 entry points, and nothing exotic is in it: no compute, no indirect draws, no manual
|
|
// barriers. See PLAN.md section 56.
|
|
//
|
|
// The types are NOT reinvented. SDL3 declares SDL_GPUTextureCreateInfo and the rest whether or not
|
|
// a backend exists on this platform, so both backends share SDL's structures and enumerations and
|
|
// only the functions are dispatched. That holds this layer to names alone.
|
|
//
|
|
// Selection is at run time, not build time: one linux-aarch64 binary ships to an RK3588 that may
|
|
// have Vulkan and to a Mali-G31 that certainly does not.
|
|
|
|
// GLSL ES source, as a shader "format". SDL_GPUShaderFormat is a bit field and SDL uses bits 0 to 5
|
|
// (PRIVATE, SPIRV, DXBC, DXIL, MSL, METALLIB), so this takes one well clear of them. A shader's
|
|
// code pointer is then the ES source string rather than a blob, and its size is ignored.
|
|
#define RGPU_SHADERFORMAT_ESSL (1u << 16)
|
|
|
|
|
|
typedef struct RenderBackendS {
|
|
SDL_GPUCommandBuffer * (*acquireCommandBuffer)(SDL_GPUDevice *device);
|
|
SDL_GPUCopyPass * (*beginCopyPass)(SDL_GPUCommandBuffer *commandBuffer);
|
|
SDL_GPURenderPass * (*beginRenderPass)(SDL_GPUCommandBuffer *commandBuffer, const SDL_GPUColorTargetInfo *colorTargetInfos, Uint32 numColorTargets, const SDL_GPUDepthStencilTargetInfo *depthStencilTargetInfo);
|
|
void (*bindFragmentSamplers)(SDL_GPURenderPass *renderPass, Uint32 firstSlot, const SDL_GPUTextureSamplerBinding *textureSamplerBindings, Uint32 numBindings);
|
|
void (*bindGraphicsPipeline)(SDL_GPURenderPass *renderPass, SDL_GPUGraphicsPipeline *graphicsPipeline);
|
|
void (*bindIndexBuffer)(SDL_GPURenderPass *renderPass, const SDL_GPUBufferBinding *binding, SDL_GPUIndexElementSize indexElementSize);
|
|
void (*bindVertexBuffers)(SDL_GPURenderPass *renderPass, Uint32 firstSlot, const SDL_GPUBufferBinding *bindings, Uint32 numBindings);
|
|
void (*bindVertexStorageBuffers)(SDL_GPURenderPass *renderPass, Uint32 firstSlot, SDL_GPUBuffer *const *storageBuffers, Uint32 numBindings);
|
|
void (*blitTexture)(SDL_GPUCommandBuffer *commandBuffer, const SDL_GPUBlitInfo *info);
|
|
bool (*cancelCommandBuffer)(SDL_GPUCommandBuffer *commandBuffer);
|
|
void (*copyTextureToTexture)(SDL_GPUCopyPass *copyPass, const SDL_GPUTextureLocation *source, const SDL_GPUTextureLocation *destination, Uint32 w, Uint32 h, Uint32 d, bool cycle);
|
|
SDL_GPUBuffer * (*createBuffer)(SDL_GPUDevice *device, const SDL_GPUBufferCreateInfo *createinfo);
|
|
SDL_GPUDevice * (*createDevice)(SDL_GPUShaderFormat formatFlags, bool debugMode, const char *name);
|
|
SDL_GPUGraphicsPipeline *(*createGraphicsPipeline)(SDL_GPUDevice *device, const SDL_GPUGraphicsPipelineCreateInfo *createinfo);
|
|
SDL_GPUSampler * (*createSampler)(SDL_GPUDevice *device, const SDL_GPUSamplerCreateInfo *createinfo);
|
|
SDL_GPUShader * (*createShader)(SDL_GPUDevice *device, const SDL_GPUShaderCreateInfo *createinfo);
|
|
SDL_GPUTexture * (*createTexture)(SDL_GPUDevice *device, const SDL_GPUTextureCreateInfo *createinfo);
|
|
SDL_GPUTransferBuffer * (*createTransferBuffer)(SDL_GPUDevice *device, const SDL_GPUTransferBufferCreateInfo *createinfo);
|
|
void (*destroyDevice)(SDL_GPUDevice *device);
|
|
void (*drawIndexedPrimitives)(SDL_GPURenderPass *renderPass, Uint32 numIndices, Uint32 numInstances, Uint32 firstIndex, Sint32 vertexOffset, Uint32 firstInstance);
|
|
void (*drawPrimitives)(SDL_GPURenderPass *renderPass, Uint32 numVertices, Uint32 numInstances, Uint32 firstVertex, Uint32 firstInstance);
|
|
void (*endCopyPass)(SDL_GPUCopyPass *copyPass);
|
|
void (*endRenderPass)(SDL_GPURenderPass *renderPass);
|
|
void (*generateMipmapsForTexture)(SDL_GPUCommandBuffer *commandBuffer, SDL_GPUTexture *texture);
|
|
const char * (*getDeviceDriver)(SDL_GPUDevice *device);
|
|
SDL_GPUShaderFormat (*getShaderFormats)(SDL_GPUDevice *device);
|
|
SDL_GPUTextureFormat (*getSwapchainTextureFormat)(SDL_GPUDevice *device, SDL_Window *window);
|
|
SDL_GPUTextureFormat (*getTextureFormatFromPixelFormat)(SDL_PixelFormat format);
|
|
void * (*mapTransferBuffer)(SDL_GPUDevice *device, SDL_GPUTransferBuffer *transferBuffer, bool cycle);
|
|
void (*pushFragmentUniformData)(SDL_GPUCommandBuffer *commandBuffer, Uint32 slotIndex, const void *data, Uint32 length);
|
|
void (*pushVertexUniformData)(SDL_GPUCommandBuffer *commandBuffer, Uint32 slotIndex, const void *data, Uint32 length);
|
|
void (*releaseBuffer)(SDL_GPUDevice *device, SDL_GPUBuffer *buffer);
|
|
void (*releaseGraphicsPipeline)(SDL_GPUDevice *device, SDL_GPUGraphicsPipeline *graphicsPipeline);
|
|
void (*releaseSampler)(SDL_GPUDevice *device, SDL_GPUSampler *sampler);
|
|
void (*releaseShader)(SDL_GPUDevice *device, SDL_GPUShader *shader);
|
|
void (*releaseTexture)(SDL_GPUDevice *device, SDL_GPUTexture *texture);
|
|
void (*releaseTransferBuffer)(SDL_GPUDevice *device, SDL_GPUTransferBuffer *transferBuffer);
|
|
void (*setScissor)(SDL_GPURenderPass *renderPass, const SDL_Rect *scissor);
|
|
void (*setStencilReference)(SDL_GPURenderPass *renderPass, Uint8 reference);
|
|
bool (*submitCommandBuffer)(SDL_GPUCommandBuffer *commandBuffer);
|
|
bool (*textureSupportsFormat)(SDL_GPUDevice *device, SDL_GPUTextureFormat format, SDL_GPUTextureType type, SDL_GPUTextureUsageFlags usage);
|
|
bool (*textureSupportsSampleCount)(SDL_GPUDevice *device, SDL_GPUTextureFormat format, SDL_GPUSampleCount sampleCount);
|
|
void (*unmapTransferBuffer)(SDL_GPUDevice *device, SDL_GPUTransferBuffer *transferBuffer);
|
|
void (*uploadToBuffer)(SDL_GPUCopyPass *copyPass, const SDL_GPUTransferBufferLocation *source, const SDL_GPUBufferRegion *destination, bool cycle);
|
|
void (*uploadToTexture)(SDL_GPUCopyPass *copyPass, const SDL_GPUTextureTransferInfo *source, const SDL_GPUTextureRegion *destination, bool cycle);
|
|
} RenderBackendT;
|
|
|
|
|
|
// Which backend is in use. RENDER_NONE means 3D and the GUI are unavailable and the engine draws
|
|
// 2D through SDL_Renderer alone, which is what a machine with no usable driver gets.
|
|
typedef enum RenderApiE {
|
|
RENDER_NONE = 0,
|
|
RENDER_GPU, // SDL_GPU: Vulkan, Direct3D 12 or Metal
|
|
RENDER_GLES // OpenGL ES 3.1, or 2.0 with the GUI only
|
|
} RenderApiT;
|
|
|
|
|
|
extern const RenderBackendT renderGlesBackend;
|
|
extern const RenderBackendT renderGpuBackend;
|
|
|
|
|
|
// The engine side. renderBegin and renderEnd bracket every frame's rgpu* calls: under SDL_GPU
|
|
// they do nothing, and under GLES they hand SDL_Renderer's context over and give it back.
|
|
RenderApiT renderApi(void);
|
|
const char *renderApiName(void);
|
|
void renderBegin(void);
|
|
void renderEnd(void);
|
|
void renderSelect(RenderApiT api, const RenderBackendT *backend, SDL_Renderer *renderer);
|
|
|
|
// The composite seam. The scene and the GUI do not draw to the swapchain; each renders into its
|
|
// own texture and hands it to SDL_Renderer to draw as an ordinary layer. Under SDL_GPU that is
|
|
// SDL_PROP_TEXTURE_CREATE_GPU_TEXTURE_POINTER and under GLES it is the twin taking a GLuint,
|
|
// SDL_PROP_TEXTURE_CREATE_OPENGLES2_TEXTURE_NUMBER, so the choice lives here rather than at each of
|
|
// the three call sites. renderTextureFor goes the other way, for a texture SDL made.
|
|
SDL_Texture *renderWrapTexture(SDL_Renderer *renderer, SDL_GPUTexture *texture, SDL_PixelFormat format, int32_t width, int32_t height);
|
|
SDL_GPUTexture *renderTextureFor(SDL_Texture *texture);
|
|
|
|
// The GLES backend's own two. renderGlesStart looks at the context SDL_Renderer already made and
|
|
// says whether it is one this backend can use; renderGlesRestore puts that context back as found.
|
|
void renderGlesRestore(void);
|
|
bool renderGlesStart(void);
|
|
Uint32 renderGlesTextureName(SDL_GPUTexture *texture);
|
|
SDL_GPUTexture *renderGlesTextureWrap(Uint32 name, int32_t width, int32_t height);
|
|
|
|
SDL_GPUCommandBuffer * rgpuAcquireCommandBuffer(SDL_GPUDevice *device);
|
|
SDL_GPUCopyPass * rgpuBeginCopyPass(SDL_GPUCommandBuffer *commandBuffer);
|
|
SDL_GPURenderPass * rgpuBeginRenderPass(SDL_GPUCommandBuffer *commandBuffer, const SDL_GPUColorTargetInfo *colorTargetInfos, Uint32 numColorTargets, const SDL_GPUDepthStencilTargetInfo *depthStencilTargetInfo);
|
|
void rgpuBindFragmentSamplers(SDL_GPURenderPass *renderPass, Uint32 firstSlot, const SDL_GPUTextureSamplerBinding *textureSamplerBindings, Uint32 numBindings);
|
|
void rgpuBindGraphicsPipeline(SDL_GPURenderPass *renderPass, SDL_GPUGraphicsPipeline *graphicsPipeline);
|
|
void rgpuBindIndexBuffer(SDL_GPURenderPass *renderPass, const SDL_GPUBufferBinding *binding, SDL_GPUIndexElementSize indexElementSize);
|
|
void rgpuBindVertexBuffers(SDL_GPURenderPass *renderPass, Uint32 firstSlot, const SDL_GPUBufferBinding *bindings, Uint32 numBindings);
|
|
void rgpuBindVertexStorageBuffers(SDL_GPURenderPass *renderPass, Uint32 firstSlot, SDL_GPUBuffer *const *storageBuffers, Uint32 numBindings);
|
|
void rgpuBlitTexture(SDL_GPUCommandBuffer *commandBuffer, const SDL_GPUBlitInfo *info);
|
|
bool rgpuCancelCommandBuffer(SDL_GPUCommandBuffer *commandBuffer);
|
|
void rgpuCopyTextureToTexture(SDL_GPUCopyPass *copyPass, const SDL_GPUTextureLocation *source, const SDL_GPUTextureLocation *destination, Uint32 w, Uint32 h, Uint32 d, bool cycle);
|
|
SDL_GPUBuffer * rgpuCreateBuffer(SDL_GPUDevice *device, const SDL_GPUBufferCreateInfo *createinfo);
|
|
SDL_GPUDevice * rgpuCreateDevice(SDL_GPUShaderFormat formatFlags, bool debugMode, const char *name);
|
|
SDL_GPUGraphicsPipeline *rgpuCreateGraphicsPipeline(SDL_GPUDevice *device, const SDL_GPUGraphicsPipelineCreateInfo *createinfo);
|
|
SDL_GPUSampler * rgpuCreateSampler(SDL_GPUDevice *device, const SDL_GPUSamplerCreateInfo *createinfo);
|
|
SDL_GPUShader * rgpuCreateShader(SDL_GPUDevice *device, const SDL_GPUShaderCreateInfo *createinfo);
|
|
SDL_GPUTexture * rgpuCreateTexture(SDL_GPUDevice *device, const SDL_GPUTextureCreateInfo *createinfo);
|
|
SDL_GPUTransferBuffer * rgpuCreateTransferBuffer(SDL_GPUDevice *device, const SDL_GPUTransferBufferCreateInfo *createinfo);
|
|
void rgpuDestroyDevice(SDL_GPUDevice *device);
|
|
void rgpuDrawIndexedPrimitives(SDL_GPURenderPass *renderPass, Uint32 numIndices, Uint32 numInstances, Uint32 firstIndex, Sint32 vertexOffset, Uint32 firstInstance);
|
|
void rgpuDrawPrimitives(SDL_GPURenderPass *renderPass, Uint32 numVertices, Uint32 numInstances, Uint32 firstVertex, Uint32 firstInstance);
|
|
void rgpuEndCopyPass(SDL_GPUCopyPass *copyPass);
|
|
void rgpuEndRenderPass(SDL_GPURenderPass *renderPass);
|
|
void rgpuGenerateMipmapsForTexture(SDL_GPUCommandBuffer *commandBuffer, SDL_GPUTexture *texture);
|
|
const char * rgpuGetDeviceDriver(SDL_GPUDevice *device);
|
|
SDL_GPUShaderFormat rgpuGetShaderFormats(SDL_GPUDevice *device);
|
|
SDL_GPUTextureFormat rgpuGetSwapchainTextureFormat(SDL_GPUDevice *device, SDL_Window *window);
|
|
SDL_GPUTextureFormat rgpuGetTextureFormatFromPixelFormat(SDL_PixelFormat format);
|
|
void * rgpuMapTransferBuffer(SDL_GPUDevice *device, SDL_GPUTransferBuffer *transferBuffer, bool cycle);
|
|
void rgpuPushFragmentUniformData(SDL_GPUCommandBuffer *commandBuffer, Uint32 slotIndex, const void *data, Uint32 length);
|
|
void rgpuPushVertexUniformData(SDL_GPUCommandBuffer *commandBuffer, Uint32 slotIndex, const void *data, Uint32 length);
|
|
void rgpuReleaseBuffer(SDL_GPUDevice *device, SDL_GPUBuffer *buffer);
|
|
void rgpuReleaseGraphicsPipeline(SDL_GPUDevice *device, SDL_GPUGraphicsPipeline *graphicsPipeline);
|
|
void rgpuReleaseSampler(SDL_GPUDevice *device, SDL_GPUSampler *sampler);
|
|
void rgpuReleaseShader(SDL_GPUDevice *device, SDL_GPUShader *shader);
|
|
void rgpuReleaseTexture(SDL_GPUDevice *device, SDL_GPUTexture *texture);
|
|
void rgpuReleaseTransferBuffer(SDL_GPUDevice *device, SDL_GPUTransferBuffer *transferBuffer);
|
|
void rgpuSetScissor(SDL_GPURenderPass *renderPass, const SDL_Rect *scissor);
|
|
void rgpuSetStencilReference(SDL_GPURenderPass *renderPass, Uint8 reference);
|
|
bool rgpuSubmitCommandBuffer(SDL_GPUCommandBuffer *commandBuffer);
|
|
bool rgpuTextureSupportsFormat(SDL_GPUDevice *device, SDL_GPUTextureFormat format, SDL_GPUTextureType type, SDL_GPUTextureUsageFlags usage);
|
|
bool rgpuTextureSupportsSampleCount(SDL_GPUDevice *device, SDL_GPUTextureFormat format, SDL_GPUSampleCount sampleCount);
|
|
void rgpuUnmapTransferBuffer(SDL_GPUDevice *device, SDL_GPUTransferBuffer *transferBuffer);
|
|
void rgpuUploadToBuffer(SDL_GPUCopyPass *copyPass, const SDL_GPUTransferBufferLocation *source, const SDL_GPUBufferRegion *destination, bool cycle);
|
|
void rgpuUploadToTexture(SDL_GPUCopyPass *copyPass, const SDL_GPUTextureTransferInfo *source, const SDL_GPUTextureRegion *destination, bool cycle);
|
|
|
|
|
|
#ifdef __cplusplus
|
|
}
|
|
#endif
|
|
|
|
#endif // RENDER_H
|