Skip to content

Commit 8304e73

Browse files
jdolanCopilot
andcommitted
Add DX improvements: buffer/texture helpers, sampler presets, Framebuffer class
- RenderDevice::createBufferWithConstMem(usage, mem, size): create + upload in one call - RenderDevice::createBufferWithData(usage, Data *): same via Objectively Data - RenderDevice::uploadBuffer(buffer, data, size, offset, cycle): dynamic per-frame upload - RenderDevice::createTextureFromSurface(surface, usage): SDL_Surface -> GPU texture - RenderDevice::samplerNearest/Linear/Anisotropic(): lazy-cached preset samplers - CopyPass::uploadData(dst, data, size, offset, cycle): batched upload within a pass - Framebuffer class: owns color+depth textures, produces SDL_GPU*TargetInfo structs - Hello.c updated to use createBufferWithConstMem and Framebuffer - Thread SDL_GPUDevice through CommandBuffer and CopyPass for transfer buffer access Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
1 parent b7d19b1 commit 8304e73

11 files changed

Lines changed: 797 additions & 70 deletions

File tree

Examples/Hello.c

Lines changed: 14 additions & 63 deletions
Original file line numberDiff line numberDiff line change
@@ -53,39 +53,6 @@ static const VertexData vertex_data[] = {
5353
{ -0.5f, -0.5f, -0.5f, 0, 1, 0 }, { 0.5f, -0.5f, -0.5f, 0, 0, 1 }, { 0.5f, -0.5f, 0.5f, 1, 0, 1 },
5454
};
5555

56-
static void upload_vertex_buffer(const RenderDevice *renderDevice, SDL_GPUBuffer *buffer) {
57-
58-
SDL_GPUTransferBuffer *transferBuffer = $(renderDevice, createTransferBuffer, &(SDL_GPUTransferBufferCreateInfo) {
59-
.usage = SDL_GPU_TRANSFERBUFFERUSAGE_UPLOAD,
60-
.size = sizeof(vertex_data),
61-
});
62-
63-
void *mapped = $(renderDevice, mapTransferBuffer, transferBuffer, false);
64-
SDL_memcpy(mapped, vertex_data, sizeof(vertex_data));
65-
$(renderDevice, unmapTransferBuffer, transferBuffer);
66-
67-
CommandBuffer *cmd = $(renderDevice, acquireCommandBuffer);
68-
CopyPass *copyPass = $(cmd, beginCopyPass);
69-
70-
$(copyPass, uploadBuffer,
71-
&(SDL_GPUTransferBufferLocation) {
72-
.transfer_buffer = transferBuffer,
73-
.offset = 0,
74-
},
75-
&(SDL_GPUBufferRegion) {
76-
.buffer = buffer,
77-
.offset = 0,
78-
.size = sizeof(vertex_data),
79-
},
80-
false);
81-
82-
release(copyPass);
83-
$(cmd, submit);
84-
release(cmd);
85-
86-
$(renderDevice, releaseTransferBuffer, transferBuffer);
87-
}
88-
8956
/**
9057
* @brief
9158
*/
@@ -100,29 +67,20 @@ int main(int argc, char **argv) {
10067

10168
$$(Resource, addResourcePath, EXAMPLES);
10269

103-
RenderDevice *renderDevice = $(alloc(RenderDevice), initWithWindow, window);
70+
RenderDevice *renderDevice = $(alloc(RenderDevice), initWithWindow, window);
10471
assert(renderDevice);
10572

106-
SDL_GPUBuffer *vertexBuffer = $(renderDevice, createBuffer, &(SDL_GPUBufferCreateInfo) {
107-
.usage = SDL_GPU_BUFFERUSAGE_VERTEX,
108-
.size = sizeof(vertex_data),
109-
});
110-
upload_vertex_buffer(renderDevice, vertexBuffer);
73+
SDL_GPUBuffer *vertexBuffer = $(renderDevice, createBufferWithConstMem,
74+
SDL_GPU_BUFFERUSAGE_VERTEX, vertex_data, sizeof(vertex_data));
11175

112-
int w = 0;
113-
int h = 0;
76+
int w = 0;
77+
int h = 0;
11478
SDL_GetWindowSizeInPixels(window, &w, &h);
11579

116-
SDL_GPUTexture *depthTexture = $(renderDevice, createTexture, &(SDL_GPUTextureCreateInfo) {
117-
.type = SDL_GPU_TEXTURETYPE_2D,
118-
.format = SDL_GPU_TEXTUREFORMAT_D16_UNORM,
119-
.usage = SDL_GPU_TEXTUREUSAGE_DEPTH_STENCIL_TARGET,
120-
.width = (Uint32) w,
121-
.height = (Uint32) h,
122-
.layer_count_or_depth = 1,
123-
.num_levels = 1,
124-
.sample_count = SDL_GPU_SAMPLECOUNT_1,
125-
}, NULL);
80+
Framebuffer *framebuffer = $(alloc(Framebuffer), initWithDevice, renderDevice,
81+
&MakeSize(w, h),
82+
SDL_GPU_TEXTUREFORMAT_INVALID,
83+
SDL_GPU_TEXTUREFORMAT_D16_UNORM);
12684

12785
SDL_GPUShader *vertexShader = $(renderDevice, loadShader, "Hello.vert", &(SDL_GPUShaderCreateInfo) {
12886
.entrypoint = "vs_main",
@@ -194,9 +152,7 @@ int main(int argc, char **argv) {
194152
});
195153

196154
$(renderDevice, releaseShader, vertexShader);
197-
vertexShader = NULL;
198155
$(renderDevice, releaseShader, fragmentShader);
199-
fragmentShader = NULL;
200156

201157
bool running = true;
202158
float angleX = 0.0f;
@@ -256,14 +212,9 @@ int main(int argc, char **argv) {
256212
.load_op = SDL_GPU_LOADOP_CLEAR,
257213
.store_op = SDL_GPU_STOREOP_STORE,
258214
};
259-
SDL_GPUDepthStencilTargetInfo depthTarget = {
260-
.texture = depthTexture,
261-
.clear_depth = 1.0f,
262-
.load_op = SDL_GPU_LOADOP_CLEAR,
263-
.store_op = SDL_GPU_STOREOP_DONT_CARE,
264-
.stencil_load_op = SDL_GPU_LOADOP_DONT_CARE,
265-
.stencil_store_op = SDL_GPU_STOREOP_DONT_CARE,
266-
};
215+
216+
SDL_GPUDepthStencilTargetInfo depthTarget = $(framebuffer, depthTargetInfo,
217+
SDL_GPU_LOADOP_CLEAR, SDL_GPU_STOREOP_DONT_CARE, 1.f);
267218

268219
RenderPass *renderPass = $(cmd, beginRenderPass, &colorTarget, 1, &depthTarget);
269220
$(renderPass, bindPipeline, pipeline);
@@ -298,8 +249,8 @@ int main(int argc, char **argv) {
298249
if (vertexBuffer) {
299250
$(renderDevice, releaseBuffer, vertexBuffer);
300251
}
301-
if (depthTexture) {
302-
$(renderDevice, releaseTexture, depthTexture);
252+
if (framebuffer) {
253+
release(framebuffer);
303254
}
304255
if (renderDevice) {
305256
release(renderDevice);

Sources/ObjectivelyGPU.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@
2626
#include <ObjectivelyGPU/CommandBuffer.h>
2727
#include <ObjectivelyGPU/ComputePass.h>
2828
#include <ObjectivelyGPU/CopyPass.h>
29+
#include <ObjectivelyGPU/Framebuffer.h>
2930
#include <ObjectivelyGPU/Mathlib.h>
3031
#include <ObjectivelyGPU/RenderDevice.h>
3132
#include <ObjectivelyGPU/RenderPass.h>

Sources/ObjectivelyGPU/CommandBuffer.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -61,7 +61,7 @@ static CopyPass *beginCopyPass(const CommandBuffer *self) {
6161
SDL_GPUCopyPass *pass = SDL_BeginGPUCopyPass(self->cmd);
6262
GPU_Assert(pass, "SDL_BeginGPUCopyPass");
6363

64-
return $(alloc(CopyPass), init, pass);
64+
return $(alloc(CopyPass), init, pass, self->device);
6565
}
6666

6767
/**

Sources/ObjectivelyGPU/CommandBuffer.h

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -68,6 +68,12 @@ struct CommandBuffer {
6868
* @brief The underlying SDL command buffer.
6969
*/
7070
SDL_GPUCommandBuffer *cmd;
71+
72+
/**
73+
* @brief The GPU device, threaded through to pass objects that need it.
74+
* @private
75+
*/
76+
SDL_GPUDevice *device;
7177
};
7278

7379
/**

Sources/ObjectivelyGPU/CopyPass.c

Lines changed: 36 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@
2222
*/
2323

2424
#include <assert.h>
25+
#include <string.h>
2526

2627
#include "CopyPass.h"
2728

@@ -77,15 +78,17 @@ static void downloadTexture(const CopyPass *self, const SDL_GPUTextureRegion *sr
7778
}
7879

7980
/**
80-
* @fn CopyPass *CopyPass::init(CopyPass *self, SDL_GPUCopyPass *pass)
81+
* @fn CopyPass *CopyPass::init(CopyPass *self, SDL_GPUCopyPass *pass, SDL_GPUDevice *device)
8182
* @memberof CopyPass
8283
*/
83-
static CopyPass *init(CopyPass *self, SDL_GPUCopyPass *pass) {
84+
static CopyPass *init(CopyPass *self, SDL_GPUCopyPass *pass, SDL_GPUDevice *device) {
8485

8586
self = (CopyPass *) super(Object, self, init);
8687
if (self) {
8788
self->pass = pass;
8889
assert(self->pass);
90+
self->device = device;
91+
assert(self->device);
8992
}
9093

9194
return self;
@@ -99,6 +102,36 @@ static void uploadBuffer(const CopyPass *self, const SDL_GPUTransferBufferLocati
99102
SDL_UploadToGPUBuffer(self->pass, src, dst, cycle);
100103
}
101104

105+
/**
106+
* @fn void CopyPass::uploadData(const CopyPass *self, SDL_GPUBuffer *dst, const void *data, Uint32 size, Uint32 offset, bool cycle)
107+
* @memberof CopyPass
108+
*/
109+
static void uploadData(const CopyPass *self, SDL_GPUBuffer *dst, const void *data, Uint32 size, Uint32 offset, bool cycle) {
110+
assert(self);
111+
assert(dst);
112+
assert(data);
113+
assert(size);
114+
115+
SDL_GPUTransferBuffer *tbuf = SDL_CreateGPUTransferBuffer(self->device, &(SDL_GPUTransferBufferCreateInfo) {
116+
.usage = SDL_GPU_TRANSFERBUFFERUSAGE_UPLOAD,
117+
.size = size,
118+
});
119+
GPU_Assert(tbuf, "SDL_CreateGPUTransferBuffer");
120+
121+
void *mapped = SDL_MapGPUTransferBuffer(self->device, tbuf, cycle);
122+
GPU_Assert(mapped, "SDL_MapGPUTransferBuffer");
123+
124+
memcpy(mapped, data, size);
125+
SDL_UnmapGPUTransferBuffer(self->device, tbuf);
126+
127+
SDL_UploadToGPUBuffer(self->pass,
128+
&(SDL_GPUTransferBufferLocation) { .transfer_buffer = tbuf },
129+
&(SDL_GPUBufferRegion) { .buffer = dst, .offset = offset, .size = size },
130+
cycle);
131+
132+
SDL_ReleaseGPUTransferBuffer(self->device, tbuf);
133+
}
134+
102135
/**
103136
* @fn void CopyPass::uploadTexture(const CopyPass *self, const SDL_GPUTextureTransferInfo *src, const SDL_GPUTextureRegion *dst, bool cycle)
104137
* @memberof CopyPass
@@ -122,6 +155,7 @@ static void initialize(Class *clazz) {
122155
((CopyPassInterface *) clazz->interface)->downloadTexture = downloadTexture;
123156
((CopyPassInterface *) clazz->interface)->init = init;
124157
((CopyPassInterface *) clazz->interface)->uploadBuffer = uploadBuffer;
158+
((CopyPassInterface *) clazz->interface)->uploadData = uploadData;
125159
((CopyPassInterface *) clazz->interface)->uploadTexture = uploadTexture;
126160
}
127161

Sources/ObjectivelyGPU/CopyPass.h

Lines changed: 26 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -69,6 +69,12 @@ struct CopyPass {
6969
* @private
7070
*/
7171
SDL_GPUCopyPass *pass;
72+
73+
/**
74+
* @brief The GPU device, used by `uploadData` to manage transfer buffers.
75+
* @private
76+
*/
77+
SDL_GPUDevice *device;
7278
};
7379

7480
/**
@@ -110,14 +116,15 @@ struct CopyPassInterface {
110116
void (*downloadTexture)(const CopyPass *self, const SDL_GPUTextureRegion *src, const SDL_GPUTextureTransferInfo *dst);
111117

112118
/**
113-
* @fn CopyPass *CopyPass::init(CopyPass *self, SDL_GPUCopyPass *pass)
119+
* @fn CopyPass *CopyPass::init(CopyPass *self, SDL_GPUCopyPass *pass, SDL_GPUDevice *device)
114120
* @brief Initializes this CopyPass wrapping the given SDL copy pass.
115121
* @param self The CopyPass.
116122
* @param pass The SDL copy pass to wrap. Must not be NULL.
123+
* @param device The SDL GPU device, used by `uploadData` to manage transfer buffers.
117124
* @return The initialized CopyPass, or NULL on failure.
118125
* @memberof CopyPass
119126
*/
120-
CopyPass *(*init)(CopyPass *self, SDL_GPUCopyPass *pass);
127+
CopyPass *(*init)(CopyPass *self, SDL_GPUCopyPass *pass, SDL_GPUDevice *device);
121128

122129
/**
123130
* @fn void CopyPass::uploadBuffer(const CopyPass *self, const SDL_GPUTransferBufferLocation *src, const SDL_GPUBufferRegion *dst, bool cycle)
@@ -130,6 +137,23 @@ struct CopyPassInterface {
130137
*/
131138
void (*uploadBuffer)(const CopyPass *self, const SDL_GPUTransferBufferLocation *src, const SDL_GPUBufferRegion *dst, bool cycle);
132139

140+
/**
141+
* @fn void CopyPass::uploadData(const CopyPass *self, SDL_GPUBuffer *dst, const void *data, Uint32 size, Uint32 offset, bool cycle)
142+
* @brief Uploads raw CPU data to a GPU buffer, managing the transfer buffer internally.
143+
* @details Allocates a temporary transfer buffer, copies @p data into it, records
144+
* the upload, and releases the transfer buffer — all within this call. Use this
145+
* to batch multiple buffer uploads into a single copy pass without manual transfer
146+
* buffer management.
147+
* @param self The CopyPass.
148+
* @param dst The GPU buffer to upload into.
149+
* @param data CPU pointer to the source data.
150+
* @param size Number of bytes to upload.
151+
* @param offset Byte offset into @p dst where the data is written.
152+
* @param cycle When true, the GPU buffer is cycled to avoid pipeline stalls.
153+
* @memberof CopyPass
154+
*/
155+
void (*uploadData)(const CopyPass *self, SDL_GPUBuffer *dst, const void *data, Uint32 size, Uint32 offset, bool cycle);
156+
133157
/**
134158
* @fn void CopyPass::uploadTexture(const CopyPass *self, const SDL_GPUTextureTransferInfo *src, const SDL_GPUTextureRegion *dst, bool cycle)
135159
* @brief Uploads data from a CPU transfer buffer to a GPU texture.

0 commit comments

Comments
 (0)