Skip to content

Commit

Permalink
glReadPixels(): support reading the stencil buffer
Browse files Browse the repository at this point in the history
  • Loading branch information
mardy committed Oct 24, 2024
1 parent 70f3c13 commit 785b33a
Show file tree
Hide file tree
Showing 5 changed files with 69 additions and 18 deletions.
1 change: 1 addition & 0 deletions src/pixel_stream.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -60,5 +60,6 @@ const struct ComponentsPerFormat _ogx_pixels_components_per_format[] = {
{ GL_BLUE, 1, { 2 }},
{ GL_ALPHA, 1, { 3 }},
{ GL_DEPTH_COMPONENT, 1, {}},
{ GL_STENCIL_INDEX, 1, { 0 }},
{ 0, }
};
13 changes: 13 additions & 0 deletions src/pixel_stream.h
Original file line number Diff line number Diff line change
Expand Up @@ -358,4 +358,17 @@ struct DepthPixelStream: public GenericPixelStream<T> {
}
};

template <typename T>
struct StencilPixelStream: public GenericPixelStream<T> {
using GenericPixelStream<T>::GenericPixelStream;
using GenericPixelStream<T>::m_write_pos;

void write(GXColor color) override {
this->d()[m_write_pos++] = glcomponent<T>(color.r)
* (1 << glparamstate.transfer_index_shift)
+ glparamstate.transfer_index_offset;
this->check_next_row();
}
};

#endif /* OPENGX_PIXEL_STREAM_H */
57 changes: 39 additions & 18 deletions src/raster.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@ POSSIBILITY OF SUCH DAMAGE.
#include "pixel_stream.h"
#include "pixels.h"
#include "state.h"
#include "stencil.h"
#include "texel.h"
#include "utils.h"

Expand Down Expand Up @@ -355,6 +356,7 @@ struct TextureReader {

Texel *new_texel_for_format(uint8_t gx_format) {
switch (gx_format) {
case GX_CTF_R4: return new TexelI4;
case GX_TF_I8: return new TexelI8;
case GX_TF_IA8: return new TexelIA8;
case GX_TF_RGBA8: return new TexelRGBA8;
Expand Down Expand Up @@ -390,6 +392,17 @@ struct PixelWriter {
case GL_FLOAT:
return new DepthPixelStream<float>(format, type);
}
} else if (format == GL_STENCIL_INDEX) {
switch (type) {
case GL_UNSIGNED_BYTE:
return new StencilPixelStream<uint8_t>(format, type);
case GL_UNSIGNED_SHORT:
return new StencilPixelStream<uint16_t>(format, type);
case GL_UNSIGNED_INT:
return new StencilPixelStream<uint32_t>(format, type);
case GL_FLOAT:
return new StencilPixelStream<float>(format, type);
}
}
switch (type) {
case GL_UNSIGNED_BYTE:
Expand Down Expand Up @@ -435,17 +448,10 @@ void glReadPixels(GLint x, GLint y, GLsizei width, GLsizei height,
{
uint8_t gxformat = 0xff;
const ReadPixelFormat *read_format = NULL;
ReadPixelFormat stencil_format;
int n_components;

switch (format) {
case GL_COLOR_INDEX:
warning("glReadPixels: GL_COLOR_INDEX not supported");
return;
case GL_STENCIL_INDEX:
warning("glReadPixels: GL_STENCIL_INDEX not implemented");
// TODO
return;
}
void *texels = nullptr;
bool must_free_texels = false;

for (int i = 0; s_read_pixel_formats[i].format != 0; i++) {
if (s_read_pixel_formats[i].format == format) {
Expand All @@ -454,15 +460,27 @@ void glReadPixels(GLint x, GLint y, GLsizei width, GLsizei height,
}
}
if (!read_format) {
warning("glReadPixels: unsupported format %04x", format);
return;
if (format == GL_STENCIL_INDEX) {
OgxEfbBuffer *stencil = _ogx_stencil_get_buffer();
stencil_format = {
format, 0,
uint8_t(GX_GetTexObjFmt(&stencil->texobj)), 1 };
read_format = &stencil_format;
texels = _ogx_efb_buffer_get_texels(stencil);
} else {
warning("glReadPixels: unsupported format %04x", format);
return;
}
}

u32 size = GX_GetTexBufferSize(width, height,
read_format->gx_dest_format, 0, GX_FALSE);
void *texels = memalign(32, size);
_ogx_efb_save_area_to_buffer(read_format->gx_copy_format, x, y,
width, height, texels, OGX_EFB_NONE);
if (!texels) {
u32 size = GX_GetTexBufferSize(width, height,
read_format->gx_dest_format, 0, GX_FALSE);
texels = memalign(32, size);
_ogx_efb_save_area_to_buffer(read_format->gx_copy_format, x, y,
width, height, texels, OGX_EFB_NONE);
must_free_texels = true;
}
TextureReader reader(read_format, texels, width, height);
PixelWriter writer(data, width, height, format, type);
for (int row = 0; row < height; row++) {
Expand All @@ -472,7 +490,10 @@ void glReadPixels(GLint x, GLint y, GLsizei width, GLsizei height,
writer.write(&pixel);
}
}
free(texels);

if (must_free_texels) {
free(texels);
}
}

void glDrawPixels(GLsizei width, GLsizei height, GLenum format, GLenum type,
Expand Down
5 changes: 5 additions & 0 deletions src/stencil.c
Original file line number Diff line number Diff line change
Expand Up @@ -630,6 +630,11 @@ void _ogx_stencil_clear()
s_stencil_texture_needs_update = false;
}

OgxEfbBuffer *_ogx_stencil_get_buffer()
{
return s_stencil_buffer;
}

void ogx_stencil_create(OgxStencilFlags flags)
{
s_wants_stencil = true;
Expand Down
11 changes: 11 additions & 0 deletions src/stencil.h
Original file line number Diff line number Diff line change
Expand Up @@ -33,11 +33,16 @@ POSSIBILITY OF SUCH DAMAGE.
#ifndef OPENGX_STENCIL_H
#define OPENGX_STENCIL_H

#include "efb.h"
#include "opengx.h"

#include <malloc.h>
#include <stdbool.h>

#ifdef __cplusplus
extern "C" {
#endif

extern OgxStencilFlags _ogx_stencil_flags;

void _ogx_stencil_enabled(void);
Expand All @@ -56,4 +61,10 @@ void _ogx_stencil_draw(OgxStencilDrawCallback callback, void *cb_data);
void _ogx_stencil_load_into_efb();
void _ogx_stencil_save_to_efb();

OgxEfbBuffer *_ogx_stencil_get_buffer(void);

#ifdef __cplusplus
} // extern C
#endif

#endif /* OPENGX_STENCIL_H */

0 comments on commit 785b33a

Please sign in to comment.