From d79884c1b4ab78b9ad232621939ab18f0070059d Mon Sep 17 00:00:00 2001 From: Spidy123222 <64176728+Spidy123222@users.noreply.github.com> Date: Mon, 9 Oct 2023 15:07:01 -0700 Subject: [PATCH] Patch 3 (#17) * Added PBOs * Update Kconfig --------- Co-authored-by: Fred Hallock --- hw/xbox/nv2a/gl/gloffscreen.h | 6 +- hw/xbox/nv2a/gl/gloffscreen_common.c | 85 +++++++++++++++++++++++----- hw/xbox/nv2a/nv2a_int.h | 2 + hw/xbox/nv2a/pgraph.c | 37 +++++++++--- target/alpha/Kconfig | 1 + 5 files changed, 109 insertions(+), 22 deletions(-) diff --git a/hw/xbox/nv2a/gl/gloffscreen.h b/hw/xbox/nv2a/gl/gloffscreen.h index caa044d3cb0..b0a2c581941 100644 --- a/hw/xbox/nv2a/gl/gloffscreen.h +++ b/hw/xbox/nv2a/gl/gloffscreen.h @@ -48,7 +48,11 @@ GloContext *glo_context_create(void); /* Destroy a previously created OpenGL context */ void glo_context_destroy(GloContext *context); -void glo_readpixels(GLenum gl_format, GLenum gl_type, +bool glo_requestpixels(GLenum gl_format, GLenum gl_type, GLuint pbo_id, + unsigned int bytes_per_pixel, unsigned int stride, + unsigned int width, unsigned int height); + +void glo_readpixels(GLenum gl_format, GLenum gl_type, GLuint pbo_id, unsigned int bytes_per_pixel, unsigned int stride, unsigned int width, unsigned int height, bool vflip, void *data); diff --git a/hw/xbox/nv2a/gl/gloffscreen_common.c b/hw/xbox/nv2a/gl/gloffscreen_common.c index f0c90df6ef6..68bb9979181 100644 --- a/hw/xbox/nv2a/gl/gloffscreen_common.c +++ b/hw/xbox/nv2a/gl/gloffscreen_common.c @@ -27,11 +27,55 @@ #include #include #include +#include #include "gloffscreen.h" +inline const char *gl_error_to_str(GLint gl_error) +{ + switch(gl_error) { + case GL_NO_ERROR: return "GL_NO_ERROR"; + case GL_INVALID_ENUM: return "GL_INVALID_ENUM"; + case GL_INVALID_VALUE: return "GL_INVALID_VALUE"; + case GL_INVALID_OPERATION: return "GL_INVALID_OPERATION"; + case GL_INVALID_INDEX: return "GL_INVALID_INDEX"; + default: return "Unknown"; + } +} -void glo_readpixels(GLenum gl_format, GLenum gl_type, +bool glo_requestpixels(GLenum gl_format, GLenum gl_type, GLuint pbo_id, + unsigned int bytes_per_pixel, unsigned int stride, + unsigned int width, unsigned int height) { + bool result = true; + + /* TODO: weird strides */ + assert(stride % bytes_per_pixel == 0); + + /* Save guest processes GL state before we ReadPixels() */ + int rl, pa; + glGetIntegerv(GL_PACK_ROW_LENGTH, &rl); + glGetIntegerv(GL_PACK_ALIGNMENT, &pa); + glPixelStorei(GL_PACK_ROW_LENGTH, stride / bytes_per_pixel); + glPixelStorei(GL_PACK_ALIGNMENT, 1); + + glBindBuffer(GL_PIXEL_PACK_BUFFER, pbo_id); + glReadPixels(0, 0, width, height, gl_format, gl_type, NULL); + GLint gl_error = glGetError(); + if(gl_error != GL_NO_ERROR) { + fprintf(stderr, "glReadPixels: %s\n", gl_error_to_str(gl_error)); + result = false; + } + + glBindBuffer(GL_PIXEL_PACK_BUFFER, 0); + + /* Restore GL state */ + glPixelStorei(GL_PACK_ROW_LENGTH, rl); + glPixelStorei(GL_PACK_ALIGNMENT, pa); + + return result; +} + +void glo_readpixels(GLenum gl_format, GLenum gl_type, GLuint pbo_id, unsigned int bytes_per_pixel, unsigned int stride, unsigned int width, unsigned int height, bool vflip, void *data) @@ -46,22 +90,35 @@ void glo_readpixels(GLenum gl_format, GLenum gl_type, glPixelStorei(GL_PACK_ROW_LENGTH, stride / bytes_per_pixel); glPixelStorei(GL_PACK_ALIGNMENT, 1); - glReadPixels(0, 0, width, height, gl_format, gl_type, data); - - if (vflip) { - GLubyte *b = (GLubyte *) data; - GLubyte *c = &((GLubyte *) data)[stride * (height - 1)]; - GLubyte *tmp = (GLubyte *) malloc(width * bytes_per_pixel); - for (int irow = 0; irow < height / 2; irow++) { - memcpy(tmp, b, width * bytes_per_pixel); - memcpy(b, c, width * bytes_per_pixel); - memcpy(c, tmp, width * bytes_per_pixel); - b += stride; - c -= stride; + glBindBuffer(GL_PIXEL_PACK_BUFFER, pbo_id); + + void *ptr = glMapBuffer(GL_PIXEL_PACK_BUFFER, GL_READ_ONLY); + GLint gl_error = glGetError(); + if(gl_error != GL_NO_ERROR) { + fprintf(stderr, "glMapBuffer: %s\n", gl_error_to_str(gl_error)); + } else { + if(ptr != NULL) { + memcpy(data, ptr, stride * height); + glUnmapBuffer(GL_PIXEL_PACK_BUFFER); + + if (vflip) { + GLubyte *b = (GLubyte *) data; + GLubyte *c = &((GLubyte *) data)[stride * (height - 1)]; + GLubyte *tmp = (GLubyte *) malloc(width * bytes_per_pixel); + for (int irow = 0; irow < height / 2; irow++) { + memcpy(tmp, b, width * bytes_per_pixel); + memcpy(b, c, width * bytes_per_pixel); + memcpy(c, tmp, width * bytes_per_pixel); + b += stride; + c -= stride; + } + free(tmp); + } } - free(tmp); } + glBindBuffer(GL_PIXEL_PACK_BUFFER, 0); + /* Restore GL state */ glPixelStorei(GL_PACK_ROW_LENGTH, rl); glPixelStorei(GL_PACK_ALIGNMENT, pa); diff --git a/hw/xbox/nv2a/nv2a_int.h b/hw/xbox/nv2a/nv2a_int.h index 31ab6d89ca6..62bb6bd9c3e 100644 --- a/hw/xbox/nv2a/nv2a_int.h +++ b/hw/xbox/nv2a/nv2a_int.h @@ -151,6 +151,8 @@ typedef struct SurfaceBinding { size_t size; GLuint gl_buffer; + GLuint pbo_id; + size_t pbo_size; bool cleared; int frame_time; diff --git a/hw/xbox/nv2a/pgraph.c b/hw/xbox/nv2a/pgraph.c index 9d9247fecac..8978d218283 100644 --- a/hw/xbox/nv2a/pgraph.c +++ b/hw/xbox/nv2a/pgraph.c @@ -5579,6 +5579,7 @@ static void pgraph_surface_invalidate(NV2AState *d, SurfaceBinding *surface) } glDeleteTextures(1, &surface->gl_buffer); + glDeleteBuffers(1, &surface->pbo_id); QTAILQ_REMOVE(&d->pgraph.surfaces, surface, entry); g_free(surface); @@ -5716,18 +5717,38 @@ static void pgraph_download_surface_data_to_buffer(NV2AState *d, gl_read_buf = swizzle_buf; } + size_t buffer_size = pg->surface_scale_factor * pg->surface_scale_factor * surface->size; if (downscale) { pg->scale_buf = (uint8_t *)g_realloc( - pg->scale_buf, pg->surface_scale_factor * pg->surface_scale_factor * - surface->size); + pg->scale_buf, buffer_size); gl_read_buf = pg->scale_buf; } - glo_readpixels( - surface->fmt.gl_format, surface->fmt.gl_type, surface->fmt.bytes_per_pixel, - pg->surface_scale_factor * surface->pitch, - pg->surface_scale_factor * surface->width, - pg->surface_scale_factor * surface->height, flip, gl_read_buf); + if(surface->pbo_size < buffer_size) { + glDeleteBuffers(1, &surface->pbo_id); + glGenBuffers(1, &surface->pbo_id); + assert(surface->pbo_id); + + glBindBuffer(GL_PIXEL_PACK_BUFFER, surface->pbo_id); + glBufferData(GL_PIXEL_PACK_BUFFER, buffer_size, NULL, GL_STREAM_READ); + glBindBuffer(GL_PIXEL_PACK_BUFFER, 0); + + surface->pbo_size = buffer_size; + } + + if(glo_requestpixels( + surface->fmt.gl_format, surface->fmt.gl_type, surface->pbo_id, + surface->fmt.bytes_per_pixel, + pg->surface_scale_factor * surface->pitch, + pg->surface_scale_factor * surface->width, + pg->surface_scale_factor * surface->height)) { + glo_readpixels( + surface->fmt.gl_format, surface->fmt.gl_type, surface->pbo_id, + surface->fmt.bytes_per_pixel, + pg->surface_scale_factor * surface->pitch, + pg->surface_scale_factor * surface->width, + pg->surface_scale_factor * surface->height, flip, gl_read_buf); + } /* FIXME: Replace this with a hw accelerated version */ if (downscale) { @@ -6028,6 +6049,8 @@ static void pgraph_populate_surface_binding_entry_sized(NV2AState *d, entry->shape = (color || !pg->color_binding) ? pg->surface_shape : pg->color_binding->shape; entry->gl_buffer = 0; + entry->pbo_id = 0; + entry->pbo_size = 0; entry->fmt = fmt; entry->color = color; entry->swizzle = diff --git a/target/alpha/Kconfig b/target/alpha/Kconfig index 267222c05b8..0e6a18ef19c 100644 --- a/target/alpha/Kconfig +++ b/target/alpha/Kconfig @@ -1,2 +1,3 @@ config ALPHA bool +