buffer: Don't set the invalidate hint when requesting read access

glMapBufferRange is documented to fail with GL_INVALID_OPERATION if
GL_MAP_INVALIDATE_BUFFER_BIT is set as well as GL_MAP_READ_BIT. I
guess this makes sense when only read access is requested because
there would be no point in reading back uninitialised data. However,
Clutter requests read/write access with the discard hint when
rendering to a CoglBitmap with Cairo. The data is new so the discard
hint makes sense but it also needs read access so that it can read
back the data it just wrote for blending.

This patch works around the GL restriction by skipping the discard
hints if read access is requested. If the buffer discard hint is set
along with read access it will recreate the buffer store as an
alternative way to discard the buffer as it does in the case where the
GL_ARB_map_buffer_range extension is not supported.

https://bugzilla.gnome.org/show_bug.cgi?id=694164

Reviewed-by: Robert Bragg <robert@linux.intel.com>

(cherry picked from commit 986675d6043e8701f2d65415cf72ffc91734debd)
This commit is contained in:
Neil Roberts 2013-02-19 13:51:34 +00:00
parent 861b119a53
commit 29983a7e2c

View File

@ -3,7 +3,7 @@
*
* An object oriented GL/GLES Abstraction/Utility Layer
*
* Copyright (C) 2010,2011,2012 Intel Corporation.
* Copyright (C) 2010,2011,2012,2013 Intel Corporation.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
@ -228,6 +228,10 @@ _cogl_buffer_gl_map_range (CoglBuffer *buffer,
gl_target = convert_bind_target_to_gl_target (target);
if ((hints & COGL_BUFFER_MAP_HINT_DISCARD_RANGE) &&
offset == 0 && size >= buffer->size)
hints |= COGL_BUFFER_MAP_HINT_DISCARD;
/* If the map buffer range extension is supported then we will
* always use it even if we are mapping the full range because the
* normal mapping function doesn't support passing the discard
@ -235,6 +239,7 @@ _cogl_buffer_gl_map_range (CoglBuffer *buffer,
if (ctx->glMapBufferRange)
{
GLbitfield gl_access = 0;
CoglBool should_recreate_store = !buffer->store_created;
if ((access & COGL_BUFFER_ACCESS_READ))
gl_access |= GL_MAP_READ_BIT;
@ -242,11 +247,25 @@ _cogl_buffer_gl_map_range (CoglBuffer *buffer,
gl_access |= GL_MAP_WRITE_BIT;
if ((hints & COGL_BUFFER_MAP_HINT_DISCARD))
gl_access |= GL_MAP_INVALIDATE_BUFFER_BIT;
if ((hints & COGL_BUFFER_MAP_HINT_DISCARD_RANGE))
{
/* glMapBufferRange generates an error if you pass the
* discard hint along with asking for read access. However
* it can make sense to ask for both if write access is also
* requested so that the application can immediately read
* back what it just wrote. To work around the restriction
* in GL we just recreate the buffer storage in that case
* which is an alternative way to indicate that the buffer
* contents can be discarded. */
if ((access & COGL_BUFFER_ACCESS_READ))
should_recreate_store = TRUE;
else
gl_access |= GL_MAP_INVALIDATE_BUFFER_BIT;
}
else if ((hints & COGL_BUFFER_MAP_HINT_DISCARD_RANGE) &&
!(access & COGL_BUFFER_ACCESS_READ))
gl_access |= GL_MAP_INVALIDATE_RANGE_BIT;
if (!buffer->store_created)
if (should_recreate_store)
{
if (!recreate_store (buffer, error))
{
@ -278,9 +297,7 @@ _cogl_buffer_gl_map_range (CoglBuffer *buffer,
* lazily allows the user of the CoglBuffer to set a hint before the
* store is created. */
if (!buffer->store_created ||
(hints & COGL_BUFFER_MAP_HINT_DISCARD) ||
((hints & COGL_BUFFER_MAP_HINT_DISCARD_RANGE) &&
offset == 0 && size >= buffer->size))
(hints & COGL_BUFFER_MAP_HINT_DISCARD))
{
if (!recreate_store (buffer, error))
{