Add fallback path for RGBA.

This is necessary for GLES devices which do not support BGRA_EXT.
This commit is contained in:
Themaister 2013-01-03 01:18:19 +01:00
parent 6f0360e6c4
commit e9cfb95900
10 changed files with 140 additions and 38 deletions

View File

@ -289,9 +289,16 @@ typedef struct driver
uintptr_t video_window;
enum rarch_display_type display_type;
// Used for 15-bit -> 16-bit conversions that take place before being passed to video driver.
struct scaler_ctx scaler;
void *scaler_out;
// Graphics driver requires RGBA byte order data (ABGR on little-endian) for 32-bit.
// This takes effect for overlay and shader cores that wants to load data into graphics driver.
// Kinda hackish to place it here, it is only used for GLES.
// TODO: Refactor this better.
bool gfx_use_rgba;
#ifdef HAVE_OVERLAY
input_overlay_t *overlay;
uint64_t overlay_state;

101
gfx/gl.c
View File

@ -912,6 +912,28 @@ static inline void gl_convert_frame_rgb16_32(gl_t *gl, void *output, const void
}
#endif
#ifdef HAVE_OPENGLES2
static inline void gl_convert_frame_argb8888_abgr8888(gl_t *gl, void *output, const void *input,
int width, int height, int in_pitch)
{
if (width != gl->scaler.in_width || height != gl->scaler.in_height)
{
gl->scaler.in_width = width;
gl->scaler.in_height = height;
gl->scaler.out_width = width;
gl->scaler.out_height = height;
gl->scaler.in_fmt = SCALER_FMT_ARGB8888;
gl->scaler.out_fmt = SCALER_FMT_ABGR8888;
gl->scaler.scaler_type = SCALER_TYPE_POINT;
scaler_ctx_gen_filter(&gl->scaler);
}
gl->scaler.in_stride = in_pitch;
gl->scaler.out_stride = width * sizeof(uint32_t);
scaler_ctx_scale(&gl->scaler, output, input);
}
#endif
static void gl_init_textures_data(gl_t *gl)
{
for (unsigned i = 0; i < TEXTURES; i++)
@ -996,27 +1018,40 @@ static inline void gl_copy_frame(gl_t *gl, const void *frame, unsigned width, un
else
#endif
{
// No GL_UNPACK_ROW_LENGTH ;(
unsigned pitch_width = pitch / gl->base_size;
if (width == pitch_width) // Happy path :D
glPixelStorei(GL_UNPACK_ALIGNMENT, get_alignment(width * gl->base_size));
// Fallback for GLES devices without GL_BGRA_EXT.
if (gl->base_size == 4 && driver.gfx_use_rgba)
{
gl_convert_frame_argb8888_abgr8888(gl, gl->conv_buffer, frame, width, height, pitch);
glTexSubImage2D(GL_TEXTURE_2D,
0, 0, 0, width, height, gl->texture_type,
gl->texture_fmt, frame);
gl->texture_fmt, gl->conv_buffer);
}
else // Slower path.
else
{
const unsigned line_bytes = width * gl->base_size;
// No GL_UNPACK_ROW_LENGTH ;(
unsigned pitch_width = pitch / gl->base_size;
if (width == pitch_width) // Happy path :D
{
glTexSubImage2D(GL_TEXTURE_2D,
0, 0, 0, width, height, gl->texture_type,
gl->texture_fmt, frame);
}
else // Slower path.
{
const unsigned line_bytes = width * gl->base_size;
uint8_t *dst = (uint8_t*)gl->conv_buffer; // This buffer is preallocated for this purpose.
const uint8_t *src = (const uint8_t*)frame;
uint8_t *dst = (uint8_t*)gl->conv_buffer; // This buffer is preallocated for this purpose.
const uint8_t *src = (const uint8_t*)frame;
for (unsigned h = 0; h < height; h++, src += pitch, dst += line_bytes)
memcpy(dst, src, line_bytes);
for (unsigned h = 0; h < height; h++, src += pitch, dst += line_bytes)
memcpy(dst, src, line_bytes);
glTexSubImage2D(GL_TEXTURE_2D,
0, 0, 0, width, height, gl->texture_type,
gl->texture_fmt, gl->conv_buffer);
glTexSubImage2D(GL_TEXTURE_2D,
0, 0, 0, width, height, gl->texture_type,
gl->texture_fmt, gl->conv_buffer);
}
}
}
#else
@ -1257,6 +1292,8 @@ static void gl_free(void *data)
glDeleteBuffers(1, &gl->pbo);
#endif
scaler_ctx_gen_reset(&gl->scaler);
#if !defined(HAVE_OPENGLES) && defined(HAVE_FFMPEG)
if (gl->pbo_readback_enable)
{
@ -1302,11 +1339,15 @@ static bool resolve_extensions(gl_t *gl)
gl->border_type = GL_CLAMP_TO_BORDER;
#endif
driver.gfx_use_rgba = false;
#ifdef HAVE_OPENGLES2
if (!gl_query_extension("BGRA8888"))
if (gl_query_extension("BGRA8888"))
RARCH_LOG("[GL]: BGRA8888 extension found for GLES.\n");
else
{
RARCH_ERR("[GL]: GLES implementation does not have BGRA8888 extension.\n");
return false;
driver.gfx_use_rgba = true;
RARCH_WARN("[GL]: GLES implementation does not have BGRA8888 extension.\n"
"32-bit path will require conversion.\n");
}
#endif
@ -1320,16 +1361,27 @@ static bool resolve_extensions(gl_t *gl)
return true;
}
static inline void gl_set_texture_fmts(gl_t *gl, bool rgb32)
{
gl->internal_fmt = rgb32 ? RARCH_GL_INTERNAL_FORMAT32 : RARCH_GL_INTERNAL_FORMAT16;
gl->texture_type = rgb32 ? RARCH_GL_TEXTURE_TYPE32 : RARCH_GL_TEXTURE_TYPE16;
gl->texture_fmt = rgb32 ? RARCH_GL_FORMAT32 : RARCH_GL_FORMAT16;
gl->base_size = rgb32 ? sizeof(uint32_t) : sizeof(uint16_t);
if (driver.gfx_use_rgba && rgb32)
{
gl->internal_fmt = GL_RGBA;
gl->texture_type = GL_RGBA;
}
}
static inline void gl_reinit_textures(gl_t *gl, const video_info_t *video)
{
unsigned old_base_size = gl->base_size;
unsigned old_width = gl->tex_w;
unsigned old_height = gl->tex_h;
gl->internal_fmt = video->rgb32 ? RARCH_GL_INTERNAL_FORMAT32 : RARCH_GL_INTERNAL_FORMAT16;
gl->texture_type = video->rgb32 ? RARCH_GL_TEXTURE_TYPE32 : RARCH_GL_TEXTURE_TYPE16;
gl->texture_fmt = video->rgb32 ? RARCH_GL_FORMAT32 : RARCH_GL_FORMAT16;
gl->base_size = video->rgb32 ? sizeof(uint32_t) : sizeof(uint16_t);
gl_set_texture_fmts(gl, video->rgb32);
gl->tex_w = gl->tex_h = RARCH_SCALE_BASE * video->input_scale;
gl->empty_buf = realloc(gl->empty_buf, sizeof(uint32_t) * gl->tex_w * gl->tex_h);
@ -1526,10 +1578,7 @@ static void *gl_init(const video_info_t *video, const input_driver_t **input, vo
else
gl->tex_filter = video->smooth ? GL_LINEAR : GL_NEAREST;
gl->internal_fmt = video->rgb32 ? RARCH_GL_INTERNAL_FORMAT32 : RARCH_GL_INTERNAL_FORMAT16;
gl->texture_type = video->rgb32 ? RARCH_GL_TEXTURE_TYPE32 : RARCH_GL_TEXTURE_TYPE16;
gl->texture_fmt = video->rgb32 ? RARCH_GL_FORMAT32 : RARCH_GL_FORMAT16;
gl->base_size = video->rgb32 ? sizeof(uint32_t) : sizeof(uint16_t);
gl_set_texture_fmts(gl, video->rgb32);
#ifndef HAVE_OPENGLES
glEnable(GL_TEXTURE_2D);
@ -1816,8 +1865,8 @@ static bool gl_overlay_load(void *data, const uint32_t *image, unsigned width, u
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glPixelStorei(GL_UNPACK_ALIGNMENT, get_alignment(width * sizeof(uint32_t)));
glTexImage2D(GL_TEXTURE_2D, 0, RARCH_GL_INTERNAL_FORMAT32,
width, height, 0, RARCH_GL_TEXTURE_TYPE32,
glTexImage2D(GL_TEXTURE_2D, 0, driver.gfx_use_rgba ? GL_RGBA : RARCH_GL_INTERNAL_FORMAT32,
width, height, 0, driver.gfx_use_rgba ? GL_RGBA : RARCH_GL_TEXTURE_TYPE32,
RARCH_GL_FORMAT32, image);
gl_overlay_tex_geom(gl, 0, 0, 1, 1); // Default. Stretch to whole screen.

View File

@ -260,6 +260,7 @@ typedef struct gl
struct gl_coords coords;
GLuint pbo;
GLenum internal_fmt;
GLenum texture_type; // RGB565 or ARGB
GLenum texture_fmt;

View File

@ -28,7 +28,8 @@
#ifdef HAVE_SDL_IMAGE
#include "SDL_image.h"
bool texture_image_load(const char *path, struct texture_image *out_img)
bool texture_image_load_argb_shift(const char *path, struct texture_image *out_img,
unsigned a_shift, unsigned r_shift, unsigned g_shift, unsigned b_shift)
{
SDL_Surface *img = IMG_Load(path);
if (!img)
@ -61,7 +62,7 @@ bool texture_image_load(const char *path, struct texture_image *out_img)
uint32_t g = (src[x] & fmt->Gmask) >> fmt->Gshift;
uint32_t b = (src[x] & fmt->Bmask) >> fmt->Bshift;
uint32_t a = (src[x] & fmt->Amask) >> fmt->Ashift;
dst[x] = (a << 24) | (r << 16) | (g << 8) | b;
dst[x] = (a << a_shift) | (r << r_shift) | (g << g_shift) | (b << b_shift);
}
}
}
@ -82,7 +83,7 @@ bool texture_image_load(const char *path, struct texture_image *out_img)
uint32_t r = (color & fmt->Rmask) >> fmt->Rshift;
uint32_t g = (color & fmt->Gmask) >> fmt->Gshift;
uint32_t b = (color & fmt->Bmask) >> fmt->Bshift;
dst[x] = (0xff << 24) | (r << 16) | (g << 8) | b;
dst[x] = (0xff << a_shift) | (r << r_shift) | (g << g_shift) | (b << b_shift);
}
}
}
@ -100,7 +101,8 @@ bool texture_image_load(const char *path, struct texture_image *out_img)
#else
bool texture_image_load(const char *path, struct texture_image *out_img)
bool texture_image_load_argb_shift(const char *path, struct texture_image *out_img,
unsigned a_shift, unsigned r_shift, unsigned g_shift, unsigned b_shift)
{
// TODO: Check more gracefully.
if (!strstr(path, ".tga"))
@ -159,7 +161,7 @@ bool texture_image_load(const char *path, struct texture_image *out_img)
uint32_t r = tmp[i * 4 + 2];
uint32_t a = tmp[i * 4 + 3];
out_img->pixels[i] = (a << 24) | (r << 16) | (g << 8) | b;
out_img->pixels[i] = (0xff << a_shift) | (r << r_shift) | (g << g_shift) | (b << b_shift);
}
}
else if (bits == 24)
@ -171,7 +173,7 @@ bool texture_image_load(const char *path, struct texture_image *out_img)
uint32_t r = tmp[i * 3 + 2];
uint32_t a = 0xff;
out_img->pixels[i] = (a << 24) | (r << 16) | (g << 8) | b;
out_img->pixels[i] = (a << a_shift) | (r << r_shift) | (g << g_shift) | (b << b_shift);
}
}
else
@ -188,3 +190,13 @@ bool texture_image_load(const char *path, struct texture_image *out_img)
}
#endif
bool texture_image_load(const char *path, struct texture_image *out_img)
{
// This interface "leak" is very ugly. FIXME: Fix this properly ...
if (driver.gfx_use_rgba)
return texture_image_load_argb_shift(path, out_img, 24, 0, 8, 16);
else
return texture_image_load_argb_shift(path, out_img, 24, 16, 8, 0);
}

View File

@ -645,6 +645,23 @@ void conv_argb8888_bgr24(void *output_, const void *input_,
}
#endif
void conv_argb8888_abgr8888(void *output_, const void *input_,
int width, int height,
int out_stride, int in_stride)
{
const uint32_t *input = (const uint32_t*)input_;
uint32_t *output = (uint32_t*)output_;
for (int h = 0; h < height; h++, output += out_stride >> 2, input += in_stride >> 2)
{
for (int w = 0; w < width; w++)
{
uint32_t col = input[w];
output[w] = ((col << 16) & 0xff0000) | ((col >> 16) & 0xff) | (col & 0xff00ff00);
}
}
}
void conv_copy(void *output_, const void *input_,
int width, int height,
int out_stride, int in_stride)

View File

@ -48,6 +48,10 @@ void conv_argb8888_bgr24(void *output, const void *input,
int width, int height,
int out_stride, int in_stride);
void conv_argb8888_abgr8888(void *output, const void *input,
int width, int height,
int out_stride, int in_stride);
void conv_0rgb1555_bgr24(void *output, const void *input,
int width, int height,
int out_stride, int in_stride);

View File

@ -86,6 +86,8 @@ static bool set_direct_pix_conv(struct scaler_ctx *ctx)
ctx->direct_pixconv = conv_0rgb1555_bgr24;
else if (ctx->in_fmt == SCALER_FMT_RGB565 && ctx->out_fmt == SCALER_FMT_BGR24)
ctx->direct_pixconv = conv_rgb565_bgr24;
else if (ctx->in_fmt == SCALER_FMT_ARGB8888 && ctx->out_fmt == SCALER_FMT_ABGR8888)
ctx->direct_pixconv = conv_argb8888_abgr8888;
else
return false;

View File

@ -25,6 +25,7 @@
enum scaler_pix_fmt
{
SCALER_FMT_ARGB8888 = 0,
SCALER_FMT_ABGR8888,
SCALER_FMT_0RGB1555,
SCALER_FMT_RGB565,
SCALER_FMT_BGR24

View File

@ -505,13 +505,19 @@ static bool load_menu_shader(void)
#define print_buf(buf, ...) snprintf(buf, sizeof(buf), __VA_ARGS__)
#ifdef HAVE_OPENGLES2
#define BORDER_FUNC GL_CLAMP_TO_EDGE
#else
#define BORDER_FUNC GL_CLAMP_TO_BORDER
#endif
static void load_texture_data(GLuint *obj, const struct texture_image *img, bool smooth)
{
glGenTextures(1, obj);
glBindTexture(GL_TEXTURE_2D, *obj);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_BORDER);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_BORDER);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, BORDER_FUNC);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, BORDER_FUNC);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, smooth ? GL_LINEAR : GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, smooth ? GL_LINEAR : GL_NEAREST);
@ -519,8 +525,8 @@ static void load_texture_data(GLuint *obj, const struct texture_image *img, bool
glPixelStorei(GL_UNPACK_ALIGNMENT, 4);
#endif
glTexImage2D(GL_TEXTURE_2D,
0, RARCH_GL_INTERNAL_FORMAT32, img->width, img->height,
0, RARCH_GL_TEXTURE_TYPE32, RARCH_GL_FORMAT32, img->pixels);
0, driver.gfx_use_rgba ? GL_RGBA : RARCH_GL_INTERNAL_FORMAT32, img->width, img->height,
0, driver.gfx_use_rgba ? GL_RGBA : RARCH_GL_TEXTURE_TYPE32, RARCH_GL_FORMAT32, img->pixels);
free(img->pixels);
}
@ -562,6 +568,7 @@ static bool load_textures(const char *cgp_path, config_file_t *conf)
fill_pathname_resolve_relative(image_path, cgp_path, path, sizeof(image_path));
RARCH_LOG("Loading image from: \"%s\".\n", image_path);
struct texture_image img;
if (!texture_image_load(image_path, &img))
{

View File

@ -481,6 +481,7 @@ static bool get_texture_image(const char *shader_path, xmlNodePtr ptr)
fill_pathname_resolve_relative(tex_path, shader_path, (const char*)filename, sizeof(tex_path));
RARCH_LOG("Loading texture image from: \"%s\" ...\n", tex_path);
if (!texture_image_load(tex_path, &img))
{
RARCH_ERR("Failed to load texture image from: \"%s\"\n", tex_path);
@ -501,8 +502,9 @@ static bool get_texture_image(const char *shader_path, xmlNodePtr ptr)
glPixelStorei(GL_UNPACK_ALIGNMENT, 4);
glTexImage2D(GL_TEXTURE_2D,
0, RARCH_GL_INTERNAL_FORMAT32,
img.width, img.height, 0, RARCH_GL_TEXTURE_TYPE32, RARCH_GL_FORMAT32, img.pixels);
0, driver.gfx_use_rgba ? GL_RGBA : RARCH_GL_INTERNAL_FORMAT32,
img.width, img.height, 0, driver.gfx_use_rgba ? GL_RGBA : RARCH_GL_TEXTURE_TYPE32,
RARCH_GL_FORMAT32, img.pixels);
pglActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, 0);