diff --git a/cogl/cogl-bitmap-conversion.c b/cogl/cogl-bitmap-conversion.c index e8a86c572..47769b6b4 100644 --- a/cogl/cogl-bitmap-conversion.c +++ b/cogl/cogl-bitmap-conversion.c @@ -319,6 +319,7 @@ _cogl_bitmap_needs_short_temp_buffer (CoglPixelFormat format) g_assert_not_reached (); case COGL_PIXEL_FORMAT_A_8: + case COGL_PIXEL_FORMAT_RG_88: case COGL_PIXEL_FORMAT_RGB_565: case COGL_PIXEL_FORMAT_RGBA_4444: case COGL_PIXEL_FORMAT_RGBA_5551: @@ -507,6 +508,35 @@ _cogl_bitmap_convert (CoglBitmap *src_bmp, return dst_bmp; } +static CoglBool +driver_can_convert (CoglContext *ctx, + CoglPixelFormat src_format, + CoglPixelFormat internal_format) +{ + if (!_cogl_has_private_feature (ctx, COGL_PRIVATE_FEATURE_FORMAT_CONVERSION)) + return FALSE; + + if (src_format == internal_format) + return TRUE; + + /* If the driver doesn't natively support alpha textures then it + * won't work correctly to convert to/from component-alpha + * textures */ + if (!_cogl_has_private_feature (ctx, COGL_PRIVATE_FEATURE_ALPHA_TEXTURES) && + (src_format == COGL_PIXEL_FORMAT_A_8 || + internal_format == COGL_PIXEL_FORMAT_A_8)) + return FALSE; + + /* Same for red-green textures. If red-green textures aren't + * supported then the internal format should never be RG_88 but we + * should still be able to convert from an RG source image */ + if (!cogl_has_feature (ctx, COGL_FEATURE_ID_TEXTURE_RG) && + src_format == COGL_PIXEL_FORMAT_RG_88) + return FALSE; + + return TRUE; +} + CoglBitmap * _cogl_bitmap_convert_for_upload (CoglBitmap *src_bmp, CoglPixelFormat internal_format, @@ -527,15 +557,7 @@ _cogl_bitmap_convert_for_upload (CoglBitmap *src_bmp, limited number of formats so we must convert using the Cogl bitmap code instead */ - /* If the driver doesn't natively support alpha textures then it - * won't work correctly to convert to/from component-alpha - * textures */ - - if (_cogl_has_private_feature (ctx, COGL_PRIVATE_FEATURE_FORMAT_CONVERSION) && - (_cogl_has_private_feature (ctx, COGL_PRIVATE_FEATURE_ALPHA_TEXTURES) || - (src_format != COGL_PIXEL_FORMAT_A_8 && - internal_format != COGL_PIXEL_FORMAT_A_8) || - src_format == internal_format)) + if (driver_can_convert (ctx, src_format, internal_format)) { /* If the source format does not have the same premult flag as the internal_format then we need to copy and convert it */ diff --git a/cogl/cogl-bitmap-packing.h b/cogl/cogl-bitmap-packing.h index e631c17f7..e2bc8a100 100644 --- a/cogl/cogl-bitmap-packing.h +++ b/cogl/cogl-bitmap-packing.h @@ -78,6 +78,22 @@ G_PASTE (_cogl_unpack_g_8_, component_size) (const uint8_t *src, } } +inline static void +G_PASTE (_cogl_unpack_rg_88_, component_size) (const uint8_t *src, + component_type *dst, + int width) +{ + while (width-- > 0) + { + dst[0] = UNPACK_BYTE (src[0]); + dst[1] = UNPACK_BYTE (src[1]); + dst[2] = 0; + dst[3] = UNPACK_BYTE (255); + dst += 4; + src += 2; + } +} + inline static void G_PASTE (_cogl_unpack_rgb_888_, component_size) (const uint8_t *src, component_type *dst, @@ -321,6 +337,9 @@ G_PASTE (_cogl_unpack_, component_size) (CoglPixelFormat format, case COGL_PIXEL_FORMAT_G_8: G_PASTE (_cogl_unpack_g_8_, component_size) (src, dst, width); break; + case COGL_PIXEL_FORMAT_RG_88: + G_PASTE (_cogl_unpack_rg_88_, component_size) (src, dst, width); + break; case COGL_PIXEL_FORMAT_RGB_888: G_PASTE (_cogl_unpack_rgb_888_, component_size) (src, dst, width); break; @@ -424,6 +443,20 @@ G_PASTE (_cogl_pack_g_8_, component_size) (const component_type *src, } } +inline static void +G_PASTE (_cogl_pack_rg_88_, component_size) (const component_type *src, + uint8_t *dst, + int width) +{ + while (width-- > 0) + { + dst[0] = PACK_BYTE (src[0]); + dst[1] = PACK_BYTE (src[1]); + src += 4; + dst += 2; + } +} + inline static void G_PASTE (_cogl_pack_rgb_888_, component_size) (const component_type *src, uint8_t *dst, @@ -665,6 +698,9 @@ G_PASTE (_cogl_pack_, component_size) (CoglPixelFormat format, case COGL_PIXEL_FORMAT_G_8: G_PASTE (_cogl_pack_g_8_, component_size) (src, dst, width); break; + case COGL_PIXEL_FORMAT_RG_88: + G_PASTE (_cogl_pack_rg_88_, component_size) (src, dst, width); + break; case COGL_PIXEL_FORMAT_RGB_888: G_PASTE (_cogl_pack_rgb_888_, component_size) (src, dst, width); break; diff --git a/cogl/cogl-context.h b/cogl/cogl-context.h index 8c99bce29..c38b86398 100644 --- a/cogl/cogl-context.h +++ b/cogl/cogl-context.h @@ -200,6 +200,9 @@ cogl_is_context (void *object); * and %COGL_FEATURE_ID_TEXTURE_NPOT_REPEAT features combined. * @COGL_FEATURE_ID_TEXTURE_RECTANGLE: Support for rectangular * textures with non-normalized texture coordinates. + * @COGL_FEATURE_ID_TEXTURE_RG: Support for + * %COGL_TEXTURE_COMPONENTS_RG as the internal components of a + * texture. * @COGL_FEATURE_ID_TEXTURE_3D: 3D texture support * @COGL_FEATURE_ID_OFFSCREEN: Offscreen rendering support * @COGL_FEATURE_ID_OFFSCREEN_MULTISAMPLE: Multisample support for @@ -263,6 +266,7 @@ typedef enum _CoglFeatureID COGL_FEATURE_ID_PRESENTATION_TIME, COGL_FEATURE_ID_FENCE, COGL_FEATURE_ID_PER_VERTEX_POINT_SIZE, + COGL_FEATURE_ID_TEXTURE_RG, /*< private >*/ _COGL_N_FEATURE_IDS /*< skip >*/ diff --git a/cogl/cogl-texture.c b/cogl/cogl-texture.c index 0e124ba1e..e2abde6ee 100644 --- a/cogl/cogl-texture.c +++ b/cogl/cogl-texture.c @@ -1377,6 +1377,14 @@ cogl_texture_allocate (CoglTexture *texture, if (texture->allocated) return TRUE; + if (texture->components == COGL_TEXTURE_COMPONENTS_RG && + !cogl_has_feature (texture->context, COGL_FEATURE_ID_TEXTURE_RG)) + _cogl_set_error (error, + COGL_TEXTURE_ERROR, + COGL_TEXTURE_ERROR_FORMAT, + "A red-green texture was requested but the driver " + "does not support them"); + texture->allocated = texture->vtable->allocate (texture, error); return texture->allocated; @@ -1396,6 +1404,11 @@ _cogl_texture_set_internal_format (CoglTexture *texture, texture->components = COGL_TEXTURE_COMPONENTS_A; return; } + else if (internal_format == COGL_PIXEL_FORMAT_RG_88) + { + texture->components = COGL_TEXTURE_COMPONENTS_RG; + return; + } else if (internal_format & COGL_DEPTH_BIT) { texture->components = COGL_TEXTURE_COMPONENTS_DEPTH; @@ -1437,6 +1450,8 @@ _cogl_texture_determine_internal_format (CoglTexture *texture, } case COGL_TEXTURE_COMPONENTS_A: return COGL_PIXEL_FORMAT_A_8; + case COGL_TEXTURE_COMPONENTS_RG: + return COGL_PIXEL_FORMAT_RG_88; case COGL_TEXTURE_COMPONENTS_RGB: if (src_format != COGL_PIXEL_FORMAT_ANY && !(src_format & COGL_A_BIT) && !(src_format & COGL_DEPTH_BIT)) diff --git a/cogl/cogl-texture.h b/cogl/cogl-texture.h index 08fa08574..d4e40c5bd 100644 --- a/cogl/cogl-texture.h +++ b/cogl/cogl-texture.h @@ -127,6 +127,9 @@ cogl_is_texture (void *object); /** * CoglTextureComponents: * @COGL_TEXTURE_COMPONENTS_A: Only the alpha component + * @COGL_TEXTURE_COMPONENTS_RG: Red and green components. Note that + * this can only be used if the %COGL_FEATURE_ID_TEXTURE_RG feature + * is advertised. * @COGL_TEXTURE_COMPONENTS_RGB: Red, green and blue components * @COGL_TEXTURE_COMPONENTS_RGBA: Red, green, blue and alpha components * @COGL_TEXTURE_COMPONENTS_DEPTH: Only a depth component @@ -138,6 +141,7 @@ cogl_is_texture (void *object); typedef enum _CoglTextureComponents { COGL_TEXTURE_COMPONENTS_A = 1, + COGL_TEXTURE_COMPONENTS_RG, COGL_TEXTURE_COMPONENTS_RGB, COGL_TEXTURE_COMPONENTS_RGBA, COGL_TEXTURE_COMPONENTS_DEPTH @@ -158,6 +162,15 @@ typedef enum _CoglTextureComponents * a %CoglBitmap or a data pointer default to the same components as * the pixel format of the data. * + * Note that the %COGL_TEXTURE_COMPONENTS_RG format is not available + * on all drivers. The availability can be determined by checking for + * the %COGL_FEATURE_ID_TEXTURE_RG feature. If this format is used on + * a driver where it is not available then %COGL_TEXTURE_ERROR_FORMAT + * will be raised when the texture is allocated. Even if the feature + * is not available then %COGL_PIXEL_FORMAT_RG_88 can still be used as + * an image format as long as %COGL_TEXTURE_COMPONENTS_RG isn't used + * as the texture's components. + * * Since: 1.18 */ void diff --git a/cogl/cogl-types.h b/cogl/cogl-types.h index 57e0e29db..3f9c23b09 100644 --- a/cogl/cogl-types.h +++ b/cogl/cogl-types.h @@ -298,6 +298,9 @@ typedef struct _CoglTextureVertex CoglTextureVertex; * CoglPixelFormat: * @COGL_PIXEL_FORMAT_ANY: Any format * @COGL_PIXEL_FORMAT_A_8: 8 bits alpha mask + * @COGL_PIXEL_FORMAT_RG_88: RG, 16 bits. Note that red-green textures + * are only available if %COGL_FEATURE_ID_TEXTURE_RG is advertised. + * See cogl_texture_set_components() for details. * @COGL_PIXEL_FORMAT_RGB_565: RGB, 16 bits * @COGL_PIXEL_FORMAT_RGBA_4444: RGBA, 16 bits * @COGL_PIXEL_FORMAT_RGBA_5551: RGBA, 16 bits @@ -355,6 +358,8 @@ typedef enum { /*< prefix=COGL_PIXEL_FORMAT >*/ COGL_PIXEL_FORMAT_YUV = 7, COGL_PIXEL_FORMAT_G_8 = 8, + COGL_PIXEL_FORMAT_RG_88 = 9, + COGL_PIXEL_FORMAT_RGB_888 = 2, COGL_PIXEL_FORMAT_BGR_888 = (2 | COGL_BGR_BIT), diff --git a/cogl/driver/gl/gl/cogl-driver-gl.c b/cogl/driver/gl/gl/cogl-driver-gl.c index 905956ad3..4134a7e65 100644 --- a/cogl/driver/gl/gl/cogl-driver-gl.c +++ b/cogl/driver/gl/gl/cogl-driver-gl.c @@ -68,6 +68,10 @@ _cogl_driver_pixel_format_from_gl_internal (CoglContext *context, *out_format = COGL_PIXEL_FORMAT_G_8; return TRUE; + case GL_RG: + *out_format = COGL_PIXEL_FORMAT_RG_88; + return TRUE; + case GL_RGB: case GL_RGB4: case GL_RGB5: case GL_RGB8: case GL_RGB10: case GL_RGB12: case GL_RGB16: case GL_R3_G3_B2: @@ -124,6 +128,26 @@ _cogl_driver_pixel_format_to_gl (CoglContext *context, gltype = GL_UNSIGNED_BYTE; break; + case COGL_PIXEL_FORMAT_RG_88: + if (cogl_has_feature (context, COGL_FEATURE_ID_TEXTURE_RG)) + { + glintformat = GL_RG; + glformat = GL_RG; + } + else + { + /* If red-green textures aren't supported then we'll use RGB + * as an internal format. Note this should only end up + * mattering for downloading the data because Cogl will + * refuse to allocate a texture with RG components if RG + * textures aren't supported */ + glintformat = GL_RGB; + glformat = GL_RGB; + required_format = COGL_PIXEL_FORMAT_RGB_888; + } + gltype = GL_UNSIGNED_BYTE; + break; + case COGL_PIXEL_FORMAT_RGB_888: glintformat = GL_RGB; glformat = GL_RGB; @@ -637,6 +661,12 @@ _cogl_driver_update_features (CoglContext *ctx, if (ctx->glFenceSync) COGL_FLAGS_SET (ctx->features, COGL_FEATURE_ID_FENCE, TRUE); + if (COGL_CHECK_GL_VERSION (gl_major, gl_minor, 3, 0) || + _cogl_check_extension ("GL_ARB_texture_rg", gl_extensions)) + COGL_FLAGS_SET (ctx->features, + COGL_FEATURE_ID_TEXTURE_RG, + TRUE); + /* Cache features */ for (i = 0; i < G_N_ELEMENTS (private_features); i++) ctx->private_features[i] |= private_features[i]; diff --git a/cogl/driver/gl/gles/cogl-driver-gles.c b/cogl/driver/gl/gles/cogl-driver-gles.c index 82c33edbc..4c4961d02 100644 --- a/cogl/driver/gl/gles/cogl-driver-gles.c +++ b/cogl/driver/gl/gles/cogl-driver-gles.c @@ -44,6 +44,12 @@ #ifndef GL_DEPTH_STENCIL #define GL_DEPTH_STENCIL 0x84F9 #endif +#ifndef GL_RG +#define GL_RG 0x8227 +#endif +#ifndef GL_RG8 +#define GL_RG8 0x822B +#endif static CoglBool _cogl_driver_pixel_format_from_gl_internal (CoglContext *context, @@ -81,6 +87,26 @@ _cogl_driver_pixel_format_to_gl (CoglContext *context, gltype = GL_UNSIGNED_BYTE; break; + case COGL_PIXEL_FORMAT_RG_88: + if (cogl_has_feature (context, COGL_FEATURE_ID_TEXTURE_RG)) + { + glintformat = GL_RG8; + glformat = GL_RG; + } + else + { + /* If red-green textures aren't supported then we'll use RGB + * as an internal format. Note this should only end up + * mattering for downloading the data because Cogl will + * refuse to allocate a texture with RG components if RG + * textures aren't supported */ + glintformat = GL_RGB; + glformat = GL_RGB; + required_format = COGL_PIXEL_FORMAT_RGB_888; + } + gltype = GL_UNSIGNED_BYTE; + break; + case COGL_PIXEL_FORMAT_BGRA_8888: case COGL_PIXEL_FORMAT_BGRA_8888_PRE: /* There is an extension to support this format */ @@ -367,6 +393,11 @@ _cogl_driver_update_features (CoglContext *context, _cogl_check_extension ("GL_OES_egl_sync", gl_extensions)) COGL_FLAGS_SET (private_features, COGL_PRIVATE_FEATURE_OES_EGL_SYNC, TRUE); + if (_cogl_check_extension ("GL_EXT_texture_rg", gl_extensions)) + COGL_FLAGS_SET (context->features, + COGL_FEATURE_ID_TEXTURE_RG, + TRUE); + /* Cache features */ for (i = 0; i < G_N_ELEMENTS (private_features); i++) context->private_features[i] |= private_features[i]; diff --git a/test-fixtures/test-utils.c b/test-fixtures/test-utils.c index 6029ddefb..59e3fd8c9 100644 --- a/test-fixtures/test-utils.c +++ b/test-fixtures/test-utils.c @@ -42,6 +42,12 @@ check_flags (TestFlags flags, return FALSE; } + if (flags & TEST_REQUIREMENT_TEXTURE_RG && + !cogl_has_feature (test_ctx, COGL_FEATURE_ID_TEXTURE_RG)) + { + return FALSE; + } + if (flags & TEST_REQUIREMENT_POINT_SPRITE && !cogl_has_feature (test_ctx, COGL_FEATURE_ID_POINT_SPRITE)) { diff --git a/test-fixtures/test-utils.h b/test-fixtures/test-utils.h index 5e40370db..9c3ced9b3 100644 --- a/test-fixtures/test-utils.h +++ b/test-fixtures/test-utils.h @@ -35,13 +35,14 @@ typedef enum _TestFlags TEST_REQUIREMENT_NPOT = 1<<2, TEST_REQUIREMENT_TEXTURE_3D = 1<<3, TEST_REQUIREMENT_TEXTURE_RECTANGLE = 1<<4, - TEST_REQUIREMENT_POINT_SPRITE = 1<<5, - TEST_REQUIREMENT_GLES2_CONTEXT = 1<<6, - TEST_REQUIREMENT_MAP_WRITE = 1<<7, - TEST_REQUIREMENT_GLSL = 1<<8, - TEST_REQUIREMENT_OFFSCREEN = 1<<9, - TEST_REQUIREMENT_FENCE = 1<<10, - TEST_REQUIREMENT_PER_VERTEX_POINT_SIZE = 1<<11 + TEST_REQUIREMENT_TEXTURE_RG = 1<<5, + TEST_REQUIREMENT_POINT_SPRITE = 1<<6, + TEST_REQUIREMENT_GLES2_CONTEXT = 1<<7, + TEST_REQUIREMENT_MAP_WRITE = 1<<8, + TEST_REQUIREMENT_GLSL = 1<<9, + TEST_REQUIREMENT_OFFSCREEN = 1<<10, + TEST_REQUIREMENT_FENCE = 1<<11, + TEST_REQUIREMENT_PER_VERTEX_POINT_SIZE = 1<<12 } TestFlags; /** diff --git a/tests/conform/Makefile.am b/tests/conform/Makefile.am index 68f922a78..b6aa552b9 100644 --- a/tests/conform/Makefile.am +++ b/tests/conform/Makefile.am @@ -67,6 +67,7 @@ test_sources = \ test-pipeline-cache-unrefs-texture.c \ test-texture-no-allocate.c \ test-pipeline-shader-state.c \ + test-texture-rg.c \ $(NULL) if !USING_EMSCRIPTEN diff --git a/tests/conform/test-conform-main.c b/tests/conform/test-conform-main.c index 83317d154..63210d02b 100644 --- a/tests/conform/test-conform-main.c +++ b/tests/conform/test-conform-main.c @@ -149,6 +149,8 @@ main (int argc, char **argv) ADD_TEST (test_texture_no_allocate, 0, 0); + ADD_TEST (test_texture_rg, TEST_REQUIREMENT_TEXTURE_RG, 0); + g_printerr ("Unknown test name \"%s\"\n", argv[1]); return 1; diff --git a/tests/conform/test-read-texture-formats.c b/tests/conform/test-read-texture-formats.c index ab2184b8e..3fa4d8eea 100644 --- a/tests/conform/test-read-texture-formats.c +++ b/tests/conform/test-read-texture-formats.c @@ -79,6 +79,23 @@ test_read_888 (CoglTexture2D *tex_2d, test_utils_compare_pixel (pixel, expected_pixel); } +static void +test_read_88 (CoglTexture2D *tex_2d, + CoglPixelFormat format, + uint32_t expected_pixel) +{ + uint8_t pixel[4]; + + pixel[2] = 0x00; + + cogl_texture_get_data (tex_2d, + format, + 2, /* rowstride */ + pixel); + + test_utils_compare_pixel (pixel, expected_pixel); +} + static void test_read_8888 (CoglTexture2D *tex_2d, CoglPixelFormat format, @@ -162,6 +179,11 @@ test_read_texture_formats (void) test_read_byte (tex_2d, COGL_PIXEL_FORMAT_G_8, 0x9c); #endif + /* We should always be able to read into an RG buffer regardless of + * whether RG textures are supported because Cogl will do the + * conversion for us */ + test_read_88 (tex_2d, COGL_PIXEL_FORMAT_RG_88, 0x123400ff); + test_read_short (tex_2d, COGL_PIXEL_FORMAT_RGB_565, 5, 0x12, 6, 0x34, 5, 0x56, -1); diff --git a/tests/conform/test-texture-rg.c b/tests/conform/test-texture-rg.c new file mode 100644 index 000000000..72a5ae930 --- /dev/null +++ b/tests/conform/test-texture-rg.c @@ -0,0 +1,74 @@ +#include + +#include + +#include "test-utils.h" + +#define TEX_WIDTH 8 +#define TEX_HEIGHT 8 + +static CoglTexture2D * +make_texture (void) +{ + uint8_t tex_data[TEX_WIDTH * TEX_HEIGHT * 2], *p = tex_data; + int x, y; + + for (y = 0; y < TEX_HEIGHT; y++) + for (x = 0; x < TEX_WIDTH; x++) + { + *(p++) = x * 256 / TEX_WIDTH; + *(p++) = y * 256 / TEX_HEIGHT; + } + + return cogl_texture_2d_new_from_data (test_ctx, + TEX_WIDTH, TEX_HEIGHT, + COGL_PIXEL_FORMAT_RG_88, + TEX_WIDTH * 2, + tex_data, + NULL); +} + +void +test_texture_rg (void) +{ + CoglPipeline *pipeline; + CoglTexture2D *tex; + int fb_width, fb_height; + int x, y; + + fb_width = cogl_framebuffer_get_width (test_fb); + fb_height = cogl_framebuffer_get_height (test_fb); + + tex = make_texture (); + + g_assert (cogl_texture_get_components (tex) == COGL_TEXTURE_COMPONENTS_RG); + + pipeline = cogl_pipeline_new (test_ctx); + + cogl_pipeline_set_layer_texture (pipeline, 0, tex); + cogl_pipeline_set_layer_filters (pipeline, + 0, + COGL_PIPELINE_FILTER_NEAREST, + COGL_PIPELINE_FILTER_NEAREST); + + cogl_framebuffer_draw_rectangle (test_fb, + pipeline, + -1.0f, 1.0f, + 1.0f, -1.0f); + + for (y = 0; y < TEX_HEIGHT; y++) + for (x = 0; x < TEX_WIDTH; x++) + { + test_utils_check_pixel_rgb (test_fb, + x * fb_width / TEX_WIDTH + + fb_width / (TEX_WIDTH * 2), + y * fb_height / TEX_HEIGHT + + fb_height / (TEX_HEIGHT * 2), + x * 256 / TEX_WIDTH, + y * 256 / TEX_HEIGHT, + 0); + } + + cogl_object_unref (pipeline); + cogl_object_unref (tex); +} diff --git a/tests/conform/test-write-texture-formats.c b/tests/conform/test-write-texture-formats.c index 859f4b4b8..d415df0a7 100644 --- a/tests/conform/test-write-texture-formats.c +++ b/tests/conform/test-write-texture-formats.c @@ -141,6 +141,11 @@ test_write_texture_formats (void) test_write_byte (test_ctx, COGL_PIXEL_FORMAT_G_8, 0x34, 0x340000ff); #endif + /* We should always be able to read from an RG buffer regardless of + * whether RG textures are supported because Cogl will do the + * conversion for us */ + test_write_bytes (test_ctx, COGL_PIXEL_FORMAT_RG_88, 0x123456ff, 0x123400ff); + test_write_short (test_ctx, COGL_PIXEL_FORMAT_RGB_565, 0x0843, 0x080819ff); test_write_short (test_ctx, COGL_PIXEL_FORMAT_RGBA_4444_PRE, 0x1234, 0x11223344); test_write_short (test_ctx, COGL_PIXEL_FORMAT_RGBA_5551_PRE, 0x0887, 0x081019ff);