/* Refresh - XNA-inspired 3D Graphics Library with modern capabilities * * Copyright (c) 2020 Evan Hemsley * * This software is provided 'as-is', without any express or implied warranty. * In no event will the authors be held liable for any damages arising from * the use of this software. * * Permission is granted to anyone to use this software for any purpose, * including commercial applications, and to alter it and redistribute it * freely, subject to the following restrictions: * * 1. The origin of this software must not be misrepresented; you must not * claim that you wrote the original software. If you use this software in a * product, an acknowledgment in the product documentation would be * appreciated but is not required. * * 2. Altered source versions must be plainly marked as such, and must not be * misrepresented as being the original software. * * 3. This notice may not be removed or altered from any source distribution. * * Evan "cosmonaut" Hemsley * */ #ifndef REFRESH_DRIVER_H #define REFRESH_DRIVER_H #include "Refresh.h" /* Windows/Visual Studio cruft */ #ifdef _WIN32 #define inline __inline #endif /* Logging */ #ifdef __cplusplus extern "C" { #endif void Refresh_LogInfo(const char *fmt, ...); void Refresh_LogWarn(const char *fmt, ...); void Refresh_LogError(const char *fmt, ...); #ifdef __cplusplus } #endif /* Internal Helper Utilities */ static inline int32_t Texture_GetBlockSize( Refresh_TextureFormat format ) { switch (format) { case REFRESH_TEXTUREFORMAT_BC1: case REFRESH_TEXTUREFORMAT_BC2: case REFRESH_TEXTUREFORMAT_BC3: case REFRESH_TEXTUREFORMAT_BC7: return 4; case REFRESH_TEXTUREFORMAT_R8: case REFRESH_TEXTUREFORMAT_R8_UINT: case REFRESH_TEXTUREFORMAT_R5G6B5: case REFRESH_TEXTUREFORMAT_B4G4R4A4: case REFRESH_TEXTUREFORMAT_A1R5G5B5: case REFRESH_TEXTUREFORMAT_R16_SFLOAT: case REFRESH_TEXTUREFORMAT_R8G8_SNORM: case REFRESH_TEXTUREFORMAT_R8G8_UINT: case REFRESH_TEXTUREFORMAT_R16_UINT: case REFRESH_TEXTUREFORMAT_R8G8B8A8: case REFRESH_TEXTUREFORMAT_R32_SFLOAT: case REFRESH_TEXTUREFORMAT_R16G16_SFLOAT: case REFRESH_TEXTUREFORMAT_R8G8B8A8_SNORM: case REFRESH_TEXTUREFORMAT_A2R10G10B10: case REFRESH_TEXTUREFORMAT_R8G8B8A8_UINT: case REFRESH_TEXTUREFORMAT_R16G16_UINT: case REFRESH_TEXTUREFORMAT_R16G16B16A16_SFLOAT: case REFRESH_TEXTUREFORMAT_R16G16B16A16: case REFRESH_TEXTUREFORMAT_R32G32_SFLOAT: case REFRESH_TEXTUREFORMAT_R16G16B16A16_UINT: case REFRESH_TEXTUREFORMAT_R32G32B32A32_SFLOAT: return 1; default: Refresh_LogError( "Unrecognized TextureFormat!" ); return 0; } } static inline uint32_t Texture_GetFormatSize( Refresh_TextureFormat format ) { switch (format) { case REFRESH_TEXTUREFORMAT_BC1: return 8; case REFRESH_TEXTUREFORMAT_BC2: case REFRESH_TEXTUREFORMAT_BC3: case REFRESH_TEXTUREFORMAT_BC7: return 16; case REFRESH_TEXTUREFORMAT_R8: case REFRESH_TEXTUREFORMAT_R8_UINT: return 1; case REFRESH_TEXTUREFORMAT_R5G6B5: case REFRESH_TEXTUREFORMAT_B4G4R4A4: case REFRESH_TEXTUREFORMAT_A1R5G5B5: case REFRESH_TEXTUREFORMAT_R16_SFLOAT: case REFRESH_TEXTUREFORMAT_R8G8_SNORM: case REFRESH_TEXTUREFORMAT_R8G8_UINT: case REFRESH_TEXTUREFORMAT_R16_UINT: return 2; case REFRESH_TEXTUREFORMAT_R8G8B8A8: case REFRESH_TEXTUREFORMAT_R32_SFLOAT: case REFRESH_TEXTUREFORMAT_R16G16_SFLOAT: case REFRESH_TEXTUREFORMAT_R8G8B8A8_SNORM: case REFRESH_TEXTUREFORMAT_A2R10G10B10: case REFRESH_TEXTUREFORMAT_R8G8B8A8_UINT: case REFRESH_TEXTUREFORMAT_R16G16_UINT: return 4; case REFRESH_TEXTUREFORMAT_R16G16B16A16_SFLOAT: case REFRESH_TEXTUREFORMAT_R16G16B16A16: case REFRESH_TEXTUREFORMAT_R32G32_SFLOAT: case REFRESH_TEXTUREFORMAT_R16G16B16A16_UINT: return 8; case REFRESH_TEXTUREFORMAT_R32G32B32A32_SFLOAT: return 16; default: Refresh_LogError( "Unrecognized TextureFormat!" ); return 0; } } static inline uint32_t PrimitiveVerts( Refresh_PrimitiveType primitiveType, uint32_t primitiveCount ) { switch (primitiveType) { case REFRESH_PRIMITIVETYPE_TRIANGLELIST: return primitiveCount * 3; case REFRESH_PRIMITIVETYPE_TRIANGLESTRIP: return primitiveCount + 2; case REFRESH_PRIMITIVETYPE_LINELIST: return primitiveCount * 2; case REFRESH_PRIMITIVETYPE_LINESTRIP: return primitiveCount + 1; case REFRESH_PRIMITIVETYPE_POINTLIST: return primitiveCount; default: Refresh_LogError( "Unrecognized primitive type!" ); return 0; } } static inline uint32_t IndexSize(Refresh_IndexElementSize size) { return (size == REFRESH_INDEXELEMENTSIZE_16BIT) ? 2 : 4; } static inline uint32_t BytesPerRow( int32_t width, Refresh_TextureFormat format ) { uint32_t blocksPerRow = width; if ( format == REFRESH_TEXTUREFORMAT_BC1 || format == REFRESH_TEXTUREFORMAT_BC2 || format == REFRESH_TEXTUREFORMAT_BC3 || format == REFRESH_TEXTUREFORMAT_BC7 ) { blocksPerRow = (width + 3) / 4; } return blocksPerRow * Texture_GetFormatSize(format); } static inline int32_t BytesPerImage( uint32_t width, uint32_t height, Refresh_TextureFormat format ) { uint32_t blocksPerRow = width; uint32_t blocksPerColumn = height; if ( format == REFRESH_TEXTUREFORMAT_BC1 || format == REFRESH_TEXTUREFORMAT_BC2 || format == REFRESH_TEXTUREFORMAT_BC3 || format == REFRESH_TEXTUREFORMAT_BC7 ) { blocksPerRow = (width + 3) / 4; blocksPerColumn = (height + 3) / 4; } return blocksPerRow * blocksPerColumn * Texture_GetFormatSize(format); } /* XNA GraphicsDevice Limits */ /* TODO: can these be adjusted for modern low-end? */ #define MAX_TEXTURE_SAMPLERS 16 #define MAX_VERTEXTEXTURE_SAMPLERS 4 #define MAX_TOTAL_SAMPLERS (MAX_TEXTURE_SAMPLERS + MAX_VERTEXTEXTURE_SAMPLERS) #define MAX_BUFFER_BINDINGS 16 #define MAX_COLOR_TARGET_BINDINGS 4 #define MAX_PRESENT_COUNT 16 /* Internal Shader Module Create Info */ typedef enum Refresh_Driver_ShaderType { REFRESH_DRIVER_SHADERTYPE_VERTEX, REFRESH_DRIVER_SHADERTYPE_FRAGMENT, REFRESH_DRIVER_SHADERTYPE_COMPUTE } Refresh_Driver_ShaderType; typedef struct Refresh_Driver_ShaderModuleCreateInfo { size_t codeSize; const uint32_t* byteCode; Refresh_Driver_ShaderType type; } Refresh_Driver_ShaderModuleCreateInfo; /* Refresh_Device Definition */ typedef struct Refresh_Renderer Refresh_Renderer; struct Refresh_Device { /* Quit */ void (*DestroyDevice)(Refresh_Device *device); /* State Creation */ Refresh_ComputePipeline* (*CreateComputePipeline)( Refresh_Renderer *driverData, Refresh_ComputeShaderInfo *computeShaderInfo ); Refresh_GraphicsPipeline* (*CreateGraphicsPipeline)( Refresh_Renderer *driverData, Refresh_GraphicsPipelineCreateInfo *pipelineCreateInfo ); Refresh_Sampler* (*CreateSampler)( Refresh_Renderer *driverData, Refresh_SamplerStateCreateInfo *samplerStateCreateInfo ); Refresh_ShaderModule* (*CreateShaderModule)( Refresh_Renderer *driverData, Refresh_Driver_ShaderModuleCreateInfo *shaderModuleCreateInfo ); Refresh_Texture* (*CreateTexture)( Refresh_Renderer *driverData, Refresh_TextureCreateInfo *textureCreateInfo ); Refresh_GpuBuffer* (*CreateGpuBuffer)( Refresh_Renderer *driverData, Refresh_BufferUsageFlags usageFlags, uint32_t sizeInBytes ); Refresh_TransferBuffer* (*CreateTransferBuffer)( Refresh_Renderer *driverData, uint32_t sizeInBytes ); /* Disposal */ void (*QueueDestroyTexture)( Refresh_Renderer *driverData, Refresh_Texture *texture ); void (*QueueDestroySampler)( Refresh_Renderer *driverData, Refresh_Sampler *sampler ); void (*QueueDestroyGpuBuffer)( Refresh_Renderer *driverData, Refresh_GpuBuffer *gpuBuffer ); void (*QueueDestroyTransferBuffer)( Refresh_Renderer *driverData, Refresh_TransferBuffer *transferBuffer ); void (*QueueDestroyShaderModule)( Refresh_Renderer *driverData, Refresh_ShaderModule *shaderModule ); void (*QueueDestroyComputePipeline)( Refresh_Renderer *driverData, Refresh_ComputePipeline *computePipeline ); void (*QueueDestroyGraphicsPipeline)( Refresh_Renderer *driverData, Refresh_GraphicsPipeline *graphicsPipeline ); /* Render Pass */ void (*BeginRenderPass)( Refresh_Renderer *driverData, Refresh_CommandBuffer *commandBuffer, Refresh_ColorAttachmentInfo *colorAttachmentInfos, uint32_t colorAttachmentCount, Refresh_DepthStencilAttachmentInfo *depthStencilAttachmentInfo ); void (*BindGraphicsPipeline)( Refresh_Renderer *driverData, Refresh_CommandBuffer *commandBuffer, Refresh_GraphicsPipeline *graphicsPipeline ); void (*SetViewport)( Refresh_Renderer *driverData, Refresh_CommandBuffer *commandBuffer, Refresh_Viewport *viewport ); void (*SetScissor)( Refresh_Renderer *driverData, Refresh_CommandBuffer *commandBuffer, Refresh_Rect *scissor ); void (*BindVertexBuffers)( Refresh_Renderer *driverData, Refresh_CommandBuffer *commandBuffer, uint32_t firstBinding, uint32_t bindingCount, Refresh_BufferBinding *pBindings ); void (*BindIndexBuffer)( Refresh_Renderer *driverData, Refresh_CommandBuffer *commandBuffer, Refresh_BufferBinding *pBinding, Refresh_IndexElementSize indexElementSize ); void (*BindVertexSamplers)( Refresh_Renderer *driverData, Refresh_CommandBuffer *commandBuffer, Refresh_TextureSamplerBinding *pBindings ); void (*BindFragmentSamplers)( Refresh_Renderer *driverData, Refresh_CommandBuffer *commandBuffer, Refresh_TextureSamplerBinding *pBindings ); void (*PushVertexShaderUniforms)( Refresh_Renderer *driverData, Refresh_CommandBuffer *commandBuffer, void *data, uint32_t dataLengthInBytes ); void (*PushFragmentShaderUniforms)( Refresh_Renderer *driverData, Refresh_CommandBuffer *commandBuffer, void *data, uint32_t dataLengthInBytes ); void (*DrawInstancedPrimitives)( Refresh_Renderer *driverData, Refresh_CommandBuffer *commandBuffer, uint32_t baseVertex, uint32_t startIndex, uint32_t primitiveCount, uint32_t instanceCount ); void (*DrawIndexedPrimitives)( Refresh_Renderer *driverData, Refresh_CommandBuffer *commandBuffer, uint32_t baseVertex, uint32_t startIndex, uint32_t primitiveCount ); void (*DrawPrimitives)( Refresh_Renderer *driverData, Refresh_CommandBuffer *commandBuffer, uint32_t vertexStart, uint32_t primitiveCount ); void (*DrawPrimitivesIndirect)( Refresh_Renderer *driverData, Refresh_CommandBuffer *commandBuffer, Refresh_GpuBuffer *gpuBuffer, uint32_t offsetInBytes, uint32_t drawCount, uint32_t stride ); void (*EndRenderPass)( Refresh_Renderer *driverData, Refresh_CommandBuffer *commandBuffer ); /* Compute Pass */ void (*BeginComputePass)( Refresh_Renderer *driverData, Refresh_CommandBuffer *commandBuffer ); void (*BindComputePipeline)( Refresh_Renderer *driverData, Refresh_CommandBuffer *commandBuffer, Refresh_ComputePipeline *computePipeline ); void (*BindComputeBuffers)( Refresh_Renderer *driverData, Refresh_CommandBuffer *commandBuffer, Refresh_ComputeBufferBinding *pBindings ); void (*BindComputeTextures)( Refresh_Renderer *driverData, Refresh_CommandBuffer *commandBuffer, Refresh_ComputeTextureBinding *pBindings ); void (*PushComputeShaderUniforms)( Refresh_Renderer *driverData, Refresh_CommandBuffer *commandBuffer, void *data, uint32_t dataLengthInBytes ); void (*DispatchCompute)( Refresh_Renderer *device, Refresh_CommandBuffer *commandBuffer, uint32_t groupCountX, uint32_t groupCountY, uint32_t groupCountZ ); void (*EndComputePass)( Refresh_Renderer *driverData, Refresh_CommandBuffer *commandBuffer ); /* TransferBuffer Set/Get */ void (*SetTransferData)( Refresh_Renderer *driverData, void* data, Refresh_TransferBuffer *transferBuffer, Refresh_BufferCopy *copyParams, Refresh_TransferOptions transferOption ); void (*GetTransferData)( Refresh_Renderer *driverData, Refresh_TransferBuffer *transferBuffer, void* data, Refresh_BufferCopy *copyParams ); /* Copy Pass */ void (*BeginCopyPass)( Refresh_Renderer *driverData, Refresh_CommandBuffer *commandBuffer ); void (*UploadToTexture)( Refresh_Renderer *driverData, Refresh_CommandBuffer *commandBuffer, Refresh_TransferBuffer *transferBuffer, Refresh_TextureRegion *textureSlice, Refresh_BufferImageCopy *copyParams, Refresh_WriteOptions writeOption ); void (*UploadToBuffer)( Refresh_Renderer *driverData, Refresh_CommandBuffer *commandBuffer, Refresh_TransferBuffer *transferBuffer, Refresh_GpuBuffer *gpuBuffer, Refresh_BufferCopy *copyParams, Refresh_WriteOptions writeOption ); void (*CopyTextureToTexture)( Refresh_Renderer *driverData, Refresh_CommandBuffer *commandBuffer, Refresh_TextureRegion *source, Refresh_TextureRegion *destination, Refresh_WriteOptions writeOption ); void (*CopyBufferToBuffer)( Refresh_Renderer *driverData, Refresh_CommandBuffer *commandBuffer, Refresh_GpuBuffer *source, Refresh_GpuBuffer *destination, Refresh_BufferCopy *copyParams, Refresh_WriteOptions writeOption ); void (*GenerateMipmaps)( Refresh_Renderer *driverData, Refresh_CommandBuffer *commandBuffer, Refresh_Texture *texture ); void (*EndCopyPass)( Refresh_Renderer *driverData, Refresh_CommandBuffer *commandBuffer ); /* Submission/Presentation */ uint8_t (*ClaimWindow)( Refresh_Renderer *driverData, void *windowHandle, Refresh_PresentMode presentMode ); void (*UnclaimWindow)( Refresh_Renderer *driverData, void *windowHandle ); void (*SetSwapchainPresentMode)( Refresh_Renderer *driverData, void *windowHandle, Refresh_PresentMode presentMode ); Refresh_TextureFormat (*GetSwapchainFormat)( Refresh_Renderer *driverData, void *windowHandle ); Refresh_CommandBuffer* (*AcquireCommandBuffer)( Refresh_Renderer *driverData ); Refresh_Texture* (*AcquireSwapchainTexture)( Refresh_Renderer *driverData, Refresh_CommandBuffer *commandBuffer, void *windowHandle, uint32_t *pWidth, uint32_t *pHeight ); void (*Submit)( Refresh_Renderer *driverData, Refresh_CommandBuffer *commandBuffer ); Refresh_Fence* (*SubmitAndAcquireFence)( Refresh_Renderer *driverData, Refresh_CommandBuffer *commandBuffer ); void (*Wait)( Refresh_Renderer *driverData ); void (*WaitForFences)( Refresh_Renderer *driverData, uint8_t waitAll, uint32_t fenceCount, Refresh_Fence **pFences ); int (*QueryFence)( Refresh_Renderer *driverData, Refresh_Fence *fence ); void (*ReleaseFence)( Refresh_Renderer *driverData, Refresh_Fence *fence ); void (*DownloadFromTexture)( Refresh_Renderer *driverData, Refresh_TextureRegion *textureSlice, Refresh_TransferBuffer *transferBuffer, Refresh_BufferImageCopy *copyParams, Refresh_TransferOptions transferOption ); void (*DownloadFromBuffer)( Refresh_Renderer *driverData, Refresh_GpuBuffer *gpuBuffer, Refresh_TransferBuffer *transferBuffer, Refresh_BufferCopy *copyParams, Refresh_TransferOptions transferOption ); /* Opaque pointer for the Driver */ Refresh_Renderer *driverData; }; #define ASSIGN_DRIVER_FUNC(func, name) \ result->func = name##_##func; #define ASSIGN_DRIVER(name) \ ASSIGN_DRIVER_FUNC(DestroyDevice, name) \ ASSIGN_DRIVER_FUNC(CreateComputePipeline, name) \ ASSIGN_DRIVER_FUNC(CreateGraphicsPipeline, name) \ ASSIGN_DRIVER_FUNC(CreateSampler, name) \ ASSIGN_DRIVER_FUNC(CreateShaderModule, name) \ ASSIGN_DRIVER_FUNC(CreateTexture, name) \ ASSIGN_DRIVER_FUNC(CreateGpuBuffer, name) \ ASSIGN_DRIVER_FUNC(CreateTransferBuffer, name) \ ASSIGN_DRIVER_FUNC(QueueDestroyTexture, name) \ ASSIGN_DRIVER_FUNC(QueueDestroySampler, name) \ ASSIGN_DRIVER_FUNC(QueueDestroyGpuBuffer, name) \ ASSIGN_DRIVER_FUNC(QueueDestroyTransferBuffer, name) \ ASSIGN_DRIVER_FUNC(QueueDestroyShaderModule, name) \ ASSIGN_DRIVER_FUNC(QueueDestroyComputePipeline, name) \ ASSIGN_DRIVER_FUNC(QueueDestroyGraphicsPipeline, name) \ ASSIGN_DRIVER_FUNC(BeginRenderPass, name) \ ASSIGN_DRIVER_FUNC(BindGraphicsPipeline, name) \ ASSIGN_DRIVER_FUNC(SetViewport, name) \ ASSIGN_DRIVER_FUNC(SetScissor, name) \ ASSIGN_DRIVER_FUNC(BindVertexBuffers, name) \ ASSIGN_DRIVER_FUNC(BindIndexBuffer, name) \ ASSIGN_DRIVER_FUNC(BindVertexSamplers, name) \ ASSIGN_DRIVER_FUNC(BindFragmentSamplers, name) \ ASSIGN_DRIVER_FUNC(PushVertexShaderUniforms, name) \ ASSIGN_DRIVER_FUNC(PushFragmentShaderUniforms, name) \ ASSIGN_DRIVER_FUNC(DrawInstancedPrimitives, name) \ ASSIGN_DRIVER_FUNC(DrawIndexedPrimitives, name) \ ASSIGN_DRIVER_FUNC(DrawPrimitives, name) \ ASSIGN_DRIVER_FUNC(DrawPrimitivesIndirect, name) \ ASSIGN_DRIVER_FUNC(EndRenderPass, name) \ ASSIGN_DRIVER_FUNC(BeginComputePass, name) \ ASSIGN_DRIVER_FUNC(BindComputePipeline, name) \ ASSIGN_DRIVER_FUNC(BindComputeBuffers, name) \ ASSIGN_DRIVER_FUNC(BindComputeTextures, name) \ ASSIGN_DRIVER_FUNC(PushComputeShaderUniforms, name) \ ASSIGN_DRIVER_FUNC(DispatchCompute, name) \ ASSIGN_DRIVER_FUNC(EndComputePass, name) \ ASSIGN_DRIVER_FUNC(SetTransferData, name) \ ASSIGN_DRIVER_FUNC(GetTransferData, name) \ ASSIGN_DRIVER_FUNC(BeginCopyPass, name) \ ASSIGN_DRIVER_FUNC(UploadToTexture, name) \ ASSIGN_DRIVER_FUNC(UploadToBuffer, name) \ ASSIGN_DRIVER_FUNC(DownloadFromTexture, name) \ ASSIGN_DRIVER_FUNC(DownloadFromBuffer, name) \ ASSIGN_DRIVER_FUNC(CopyTextureToTexture, name) \ ASSIGN_DRIVER_FUNC(CopyBufferToBuffer, name) \ ASSIGN_DRIVER_FUNC(GenerateMipmaps, name) \ ASSIGN_DRIVER_FUNC(EndCopyPass, name) \ ASSIGN_DRIVER_FUNC(ClaimWindow, name) \ ASSIGN_DRIVER_FUNC(UnclaimWindow, name) \ ASSIGN_DRIVER_FUNC(SetSwapchainPresentMode, name) \ ASSIGN_DRIVER_FUNC(GetSwapchainFormat, name) \ ASSIGN_DRIVER_FUNC(AcquireCommandBuffer, name) \ ASSIGN_DRIVER_FUNC(AcquireSwapchainTexture, name) \ ASSIGN_DRIVER_FUNC(Submit, name) \ ASSIGN_DRIVER_FUNC(SubmitAndAcquireFence, name) \ ASSIGN_DRIVER_FUNC(Wait, name) \ ASSIGN_DRIVER_FUNC(WaitForFences, name) \ ASSIGN_DRIVER_FUNC(QueryFence, name) \ ASSIGN_DRIVER_FUNC(ReleaseFence, name) typedef struct Refresh_Driver { const char *Name; uint8_t (*PrepareDriver)(uint32_t *flags); Refresh_Device* (*CreateDevice)( uint8_t debugMode ); } Refresh_Driver; extern Refresh_Driver VulkanDriver; extern Refresh_Driver D3D11Driver; extern Refresh_Driver PS5Driver; #endif /* REFRESH_DRIVER_H */ /* vim: set noexpandtab shiftwidth=8 tabstop=8: */