renderer: simplify async readback API; use glMapBufferRange
glGetBufferSubData is not available on GLES
This commit is contained in:
parent
d03b2eb38c
commit
783172861a
7 changed files with 41 additions and 46 deletions
|
@ -644,21 +644,17 @@ void r_framebuffer_read_async(
|
|||
Framebuffer *framebuffer,
|
||||
FramebufferAttachment attachment,
|
||||
IntRect region,
|
||||
Allocator *allocator,
|
||||
Pixmap *out_pixmap,
|
||||
void *userdata,
|
||||
FramebufferReadAsyncCallback callback
|
||||
) {
|
||||
B.framebuffer_read_async(
|
||||
framebuffer, attachment, region, allocator, out_pixmap, userdata, callback
|
||||
framebuffer, attachment, region, userdata, callback
|
||||
);
|
||||
}
|
||||
|
||||
void r_framebuffer_read_viewport_async(
|
||||
Framebuffer *framebuffer,
|
||||
FramebufferAttachment attachment,
|
||||
Allocator *allocator,
|
||||
Pixmap *out_pixmap,
|
||||
void *userdata,
|
||||
FramebufferReadAsyncCallback callback
|
||||
) {
|
||||
|
@ -673,7 +669,7 @@ void r_framebuffer_read_viewport_async(
|
|||
};
|
||||
|
||||
r_framebuffer_read_async(
|
||||
framebuffer, attachment, region, allocator, out_pixmap, userdata, callback);
|
||||
framebuffer, attachment, region, userdata, callback);
|
||||
}
|
||||
|
||||
VertexBuffer* r_vertex_buffer_create(size_t capacity, void *data) {
|
||||
|
|
|
@ -219,7 +219,7 @@ enum {
|
|||
FRAMEBUFFER_MAX_OUTPUTS = FRAMEBUFFER_MAX_COLOR_ATTACHMENTS,
|
||||
};
|
||||
|
||||
typedef void (*FramebufferReadAsyncCallback)(Allocator *allocator, Pixmap *pixmap, void *userdata);
|
||||
typedef void (*FramebufferReadAsyncCallback)(const Pixmap *pixmap, void *userdata);
|
||||
|
||||
typedef enum Primitive {
|
||||
PRIM_POINTS,
|
||||
|
@ -775,8 +775,8 @@ void r_framebuffer_destroy(Framebuffer *fb) attr_nonnull(1);
|
|||
void r_framebuffer_clear(Framebuffer *fb, BufferKindFlags flags, const Color *colorval, float depthval);
|
||||
void r_framebuffer_copy(Framebuffer *dst, Framebuffer *src, BufferKindFlags flags) attr_nonnull_all;
|
||||
IntExtent r_framebuffer_get_size(Framebuffer *fb);
|
||||
void r_framebuffer_read_async(Framebuffer *framebuffer, FramebufferAttachment attachment, IntRect region, Allocator *allocator, Pixmap *out_pixmap, void *userdata, FramebufferReadAsyncCallback callback);
|
||||
void r_framebuffer_read_viewport_async(Framebuffer *framebuffer, FramebufferAttachment attachment, Allocator *allocator, Pixmap *out_pixmap, void *userdata, FramebufferReadAsyncCallback callback);
|
||||
void r_framebuffer_read_async(Framebuffer *framebuffer, FramebufferAttachment attachment, IntRect region, void *userdata, FramebufferReadAsyncCallback callback);
|
||||
void r_framebuffer_read_viewport_async(Framebuffer *framebuffer, FramebufferAttachment attachment, void *userdata, FramebufferReadAsyncCallback callback);
|
||||
|
||||
void r_framebuffer(Framebuffer *fb);
|
||||
Framebuffer* r_framebuffer_current(void);
|
||||
|
|
|
@ -92,7 +92,7 @@ typedef struct RendererFuncs {
|
|||
void (*framebuffer_clear)(Framebuffer *framebuffer, BufferKindFlags flags, const Color *colorval, float depthval);
|
||||
void (*framebuffer_copy)(Framebuffer *dst, Framebuffer *src, BufferKindFlags flags);
|
||||
IntExtent (*framebuffer_get_size)(Framebuffer *framebuffer);
|
||||
void (*framebuffer_read_async)(Framebuffer *framebuffer, FramebufferAttachment attachment, IntRect region, Allocator *allocator, Pixmap *out_pixmap, void *userdata, FramebufferReadAsyncCallback callback);
|
||||
void (*framebuffer_read_async)(Framebuffer *framebuffer, FramebufferAttachment attachment, IntRect region, void *userdata, FramebufferReadAsyncCallback callback);
|
||||
|
||||
void (*framebuffer)(Framebuffer *framebuffer);
|
||||
Framebuffer* (*framebuffer_current)(void);
|
||||
|
|
|
@ -250,14 +250,17 @@ IntExtent gl33_framebuffer_get_effective_size(Framebuffer *framebuffer) {
|
|||
}
|
||||
|
||||
typedef struct FramebufferReadRequest {
|
||||
Pixmap *target;
|
||||
Allocator *allocator;
|
||||
void *userdata;
|
||||
FramebufferReadAsyncCallback callback;
|
||||
void *userdata;
|
||||
GLuint pbo;
|
||||
GLsync sync;
|
||||
GLenum sync_result;
|
||||
GLbitfield sync_flags;
|
||||
struct {
|
||||
uint width;
|
||||
uint height;
|
||||
PixmapFormat format;
|
||||
} transfer;
|
||||
} FramebufferReadRequest;
|
||||
|
||||
static FramebufferReadRequest read_requests[4];
|
||||
|
@ -267,23 +270,27 @@ static void handle_read_request(FramebufferReadRequest *rq, bool ok) {
|
|||
rq->sync = NULL;
|
||||
rq->sync_result = GL_NONE;
|
||||
|
||||
auto pxm = rq->target;
|
||||
|
||||
if(ok) {
|
||||
// data_size already specified
|
||||
pxm->data.untyped = allocator_alloc(rq->allocator, pxm->data_size);
|
||||
assert(rq->pbo != 0);
|
||||
auto prev_pbo = gl33_buffer_current(GL33_BUFFER_BINDING_PIXEL_PACK);
|
||||
gl33_bind_buffer(GL33_BUFFER_BINDING_PIXEL_PACK, rq->pbo);
|
||||
gl33_sync_buffer(GL33_BUFFER_BINDING_PIXEL_PACK);
|
||||
glGetBufferSubData(GL_PIXEL_PACK_BUFFER, 0, pxm->data_size, pxm->data.untyped);
|
||||
|
||||
auto data_size = pixmap_data_size(rq->transfer.format, rq->transfer.width, rq->transfer.height);
|
||||
rq->callback(&(Pixmap) {
|
||||
.width = rq->transfer.width,
|
||||
.height = rq->transfer.height,
|
||||
.format = rq->transfer.format,
|
||||
.origin = PIXMAP_ORIGIN_BOTTOMLEFT,
|
||||
.data_size = data_size,
|
||||
.data.untyped = glMapBufferRange(GL_PIXEL_PACK_BUFFER, 0, data_size, GL_MAP_READ_BIT)
|
||||
}, rq->userdata);
|
||||
|
||||
glUnmapBuffer(GL_PIXEL_PACK_BUFFER);
|
||||
gl33_bind_buffer(GL33_BUFFER_BINDING_PIXEL_PACK, prev_pbo);
|
||||
} else {
|
||||
pxm->data_size = 0;
|
||||
pxm->data.untyped = NULL;
|
||||
rq->callback(NULL, rq->userdata);
|
||||
}
|
||||
|
||||
rq->callback(rq->allocator, rq->target, rq->userdata);
|
||||
}
|
||||
|
||||
static GLenum sync_read_request(FramebufferReadRequest *rq, GLuint64 timeout) {
|
||||
|
@ -363,8 +370,6 @@ void gl33_framebuffer_read_async(
|
|||
Framebuffer *framebuffer,
|
||||
FramebufferAttachment attachment,
|
||||
IntRect region,
|
||||
Allocator *allocator,
|
||||
Pixmap *pxm,
|
||||
void *userdata,
|
||||
FramebufferReadAsyncCallback callback
|
||||
) {
|
||||
|
@ -394,16 +399,10 @@ void gl33_framebuffer_read_async(
|
|||
assume(fmtinfo != NULL);
|
||||
}
|
||||
|
||||
*pxm = (Pixmap) {
|
||||
.width = region.w,
|
||||
.height = region.h,
|
||||
.format = fmtinfo->transfer_format.pixmap_format,
|
||||
.origin = PIXMAP_ORIGIN_BOTTOMLEFT,
|
||||
};
|
||||
|
||||
auto rq = alloc_read_request();
|
||||
rq->allocator = allocator;
|
||||
rq->target = pxm;
|
||||
rq->transfer.width = region.w;
|
||||
rq->transfer.height = region.h;
|
||||
rq->transfer.format = fmtinfo->transfer_format.pixmap_format;
|
||||
rq->userdata = userdata;
|
||||
rq->callback = callback;
|
||||
rq->sync_flags = GL_SYNC_FLUSH_COMMANDS_BIT;
|
||||
|
@ -412,12 +411,11 @@ void gl33_framebuffer_read_async(
|
|||
glGenBuffers(1, &rq->pbo);
|
||||
}
|
||||
|
||||
pxm->data_size = pixmap_data_size(pxm->format, pxm->width, pxm->height);
|
||||
|
||||
auto prev_pbo = gl33_buffer_current(GL33_BUFFER_BINDING_PIXEL_PACK);
|
||||
gl33_bind_buffer(GL33_BUFFER_BINDING_PIXEL_PACK, rq->pbo);
|
||||
gl33_sync_buffer(GL33_BUFFER_BINDING_PIXEL_PACK);
|
||||
glBufferData(GL_PIXEL_PACK_BUFFER, pxm->data_size, NULL, GL_STREAM_READ);
|
||||
auto data_size = pixmap_data_size(rq->transfer.format, rq->transfer.width, rq->transfer.height);
|
||||
glBufferData(GL_PIXEL_PACK_BUFFER, data_size, NULL, GL_STREAM_READ);
|
||||
|
||||
glReadPixels(
|
||||
region.x, region.y, region.w, region.h,
|
||||
|
|
|
@ -41,8 +41,6 @@ void gl33_framebuffer_read_async(
|
|||
Framebuffer *framebuffer,
|
||||
FramebufferAttachment attachment,
|
||||
IntRect region,
|
||||
Allocator *allocator,
|
||||
Pixmap *pxm,
|
||||
void *userdata,
|
||||
FramebufferReadAsyncCallback callback
|
||||
);
|
||||
|
|
|
@ -133,10 +133,8 @@ static void null_framebuffer_clear(Framebuffer *framebuffer, BufferKindFlags fla
|
|||
static void null_framebuffer_copy(Framebuffer *dst, Framebuffer *src, BufferKindFlags flags) { }
|
||||
static IntExtent null_framebuffer_get_size(Framebuffer *framebuffer) { return (IntExtent) { 64, 64 }; }
|
||||
|
||||
static void null_framebuffer_read_async(Framebuffer *framebuffer, FramebufferAttachment attachment, IntRect region, Allocator *allocator, Pixmap *out_pixmap, void *userdata, FramebufferReadAsyncCallback callback) {
|
||||
out_pixmap->data.untyped = NULL;
|
||||
out_pixmap->data_size = 0;
|
||||
callback(allocator, out_pixmap, userdata);
|
||||
static void null_framebuffer_read_async(Framebuffer *framebuffer, FramebufferAttachment attachment, IntRect region, void *userdata, FramebufferReadAsyncCallback callback) {
|
||||
callback(NULL, userdata);
|
||||
}
|
||||
|
||||
static int64_t null_vertex_buffer_stream_seek(SDL_RWops *rw, int64_t offset, int whence) { return 0; }
|
||||
|
|
13
src/video.c
13
src/video.c
|
@ -690,12 +690,17 @@ static void video_screenshot_free_task_data(void *arg) {
|
|||
mem_free(tdata);
|
||||
}
|
||||
|
||||
static void video_take_screenshot_callback(Allocator *allocator, Pixmap *px, void *userdata) {
|
||||
if(!px->data.untyped) {
|
||||
static void video_take_screenshot_callback(const Pixmap *px, void *userdata) {
|
||||
if(!px) {
|
||||
log_error("Failed to capture image");
|
||||
return;
|
||||
}
|
||||
|
||||
ScreenshotTaskData *tdata = userdata;
|
||||
// NOTE: could convert formats here to avoid a double copy,
|
||||
// but it's faster to do it on the task thread.
|
||||
pixmap_copy_alloc(px, &tdata->image);
|
||||
|
||||
task_detach(taskmgr_global_submit((TaskParams) {
|
||||
.callback = video_screenshot_task,
|
||||
.userdata = userdata,
|
||||
|
@ -721,7 +726,7 @@ void video_take_screenshot(bool viewport_only) {
|
|||
}
|
||||
|
||||
r_framebuffer_read_viewport_async(
|
||||
fb, attachment, &default_allocator, &tdata->image, tdata, video_take_screenshot_callback);
|
||||
fb, attachment, tdata, video_take_screenshot_callback);
|
||||
}
|
||||
|
||||
static void video_take_framedump(void) {
|
||||
|
@ -741,7 +746,7 @@ static void video_take_framedump(void) {
|
|||
tdata->frame_num = video.framedump.frame_count++;
|
||||
|
||||
r_framebuffer_read_viewport_async(
|
||||
fb, attachment, &default_allocator, &tdata->image, tdata, video_take_screenshot_callback);
|
||||
fb, attachment, tdata, video_take_screenshot_callback);
|
||||
}
|
||||
|
||||
bool video_is_resizable(void) {
|
||||
|
|
Loading…
Reference in a new issue