Skip to content

Commit

Permalink
Patch 3 (#17)
Browse files Browse the repository at this point in the history
* Added PBOs

* Update Kconfig

---------

Co-authored-by: Fred Hallock <[email protected]>
  • Loading branch information
Spidy123222 and faha223 authored Oct 9, 2023
1 parent edecb41 commit d79884c
Show file tree
Hide file tree
Showing 5 changed files with 109 additions and 22 deletions.
6 changes: 5 additions & 1 deletion hw/xbox/nv2a/gl/gloffscreen.h
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down
85 changes: 71 additions & 14 deletions hw/xbox/nv2a/gl/gloffscreen_common.c
Original file line number Diff line number Diff line change
Expand Up @@ -27,11 +27,55 @@
#include <string.h>
#include <assert.h>
#include <stdlib.h>
#include <stdio.h>

#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)
Expand All @@ -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);
Expand Down
2 changes: 2 additions & 0 deletions hw/xbox/nv2a/nv2a_int.h
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down
37 changes: 30 additions & 7 deletions hw/xbox/nv2a/pgraph.c
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down Expand Up @@ -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) {
Expand Down Expand Up @@ -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 =
Expand Down
1 change: 1 addition & 0 deletions target/alpha/Kconfig
Original file line number Diff line number Diff line change
@@ -1,2 +1,3 @@
config ALPHA
bool

0 comments on commit d79884c

Please sign in to comment.