--- mesa-11.2.0/src/gallium/state_trackers/osmesa/osmesa.c.orig 2016-03-13 19:35:33.000000000 +0100 +++ mesa-11.2.0/src/gallium/state_trackers/osmesa/osmesa.c 2016-04-21 17:41:01.000000000 +0200 @@ -52,6 +52,7 @@ #include #include "GL/osmesa.h" +#include "main/context.h" #include "glapi/glapi.h" /* for OSMesaGetProcAddress below */ #include "pipe/p_context.h" @@ -69,6 +70,7 @@ #include "state_tracker/st_api.h" #include "state_tracker/st_gl_api.h" +#include "state_tracker/st_context.h" @@ -86,13 +88,13 @@ struct pipe_resource *textures[ST_ATTACHMENT_COUNT]; void *map; - - struct osmesa_buffer *next; /**< next in linked list */ }; struct osmesa_context { + struct st_api* api; + struct st_manager* manager; struct st_context_iface *stctx; boolean ever_used; /*< Has this context ever been current? */ @@ -114,17 +116,6 @@ /** - * Linked list of all osmesa_buffers. - * We can re-use an osmesa_buffer from one OSMesaMakeCurrent() call to - * the next unless the color/depth/stencil/accum formats change. - * We have to do this to be compatible with the original OSMesa implementation - * because some apps call OSMesaMakeCurrent() several times during rendering - * a frame. - */ -static struct osmesa_buffer *BufferList = NULL; - - -/** * Called from the ST manager. */ static int @@ -135,39 +126,6 @@ } -/** - * Create/return singleton st_api object. - */ -static struct st_api * -get_st_api(void) -{ - static struct st_api *stapi = NULL; - if (!stapi) { - stapi = st_gl_api_create(); - } - return stapi; -} - - -/** - * Create/return a singleton st_manager object. - */ -static struct st_manager * -get_st_manager(void) -{ - static struct st_manager *stmgr = NULL; - if (!stmgr) { - stmgr = CALLOC_STRUCT(st_manager); - if (stmgr) { - stmgr->screen = osmesa_create_screen(); - stmgr->get_param = osmesa_st_get_param; - stmgr->get_egl_image = NULL; - } - } - return stmgr; -} - - static inline boolean little_endian(void) { @@ -319,6 +277,11 @@ unsigned y, bytes, bpp; int dst_stride; + assert(res); + if (!res) { + return FALSE; + } + if (osmesa->pp) { struct pipe_resource *zsbuf = NULL; unsigned i; @@ -387,7 +350,8 @@ unsigned count, struct pipe_resource **out) { - struct pipe_screen *screen = get_st_manager()->screen; + OSMesaContext osmesa = stctx->st_manager_private; + struct pipe_screen *screen = osmesa->manager->screen; enum st_attachment_type i; struct osmesa_buffer *osbuffer = stfbi_to_osbuffer(stfbi); struct pipe_resource templat; @@ -470,45 +434,18 @@ osmesa_init_st_visual(&osbuffer->visual, color_format, ds_format, accum_format); - - /* insert into linked list */ - osbuffer->next = BufferList; - BufferList = osbuffer; } return osbuffer; } -/** - * Search linked list for a buffer with matching pixel formats and size. - */ -static struct osmesa_buffer * -osmesa_find_buffer(enum pipe_format color_format, - enum pipe_format ds_format, - enum pipe_format accum_format, - GLsizei width, GLsizei height) -{ - struct osmesa_buffer *b; - - /* Check if we already have a suitable buffer for the given formats */ - for (b = BufferList; b; b = b->next) { - if (b->visual.color_format == color_format && - b->visual.depth_stencil_format == ds_format && - b->visual.accum_format == accum_format && - b->width == width && - b->height == height) { - return b; - } - } - return NULL; -} - - static void osmesa_destroy_buffer(struct osmesa_buffer *osbuffer) { - FREE(osbuffer->stfb); + if (osbuffer) { + FREE(osbuffer->stfb); + } FREE(osbuffer); } @@ -572,7 +509,6 @@ struct st_context_iface *st_shared; enum st_context_error st_error = 0; struct st_context_attribs attribs; - struct st_api *stapi = get_st_api(); GLenum format = GL_RGBA; int depthBits = 0, stencilBits = 0, accumBits = 0; int profile = OSMESA_COMPAT_PROFILE, version_major = 1, version_minor = 0; @@ -685,9 +621,21 @@ osmesa->depth_stencil_format, osmesa->accum_format); - osmesa->stctx = stapi->create_context(stapi, get_st_manager(), + osmesa->api = st_gl_api_create(); + osmesa->manager = CALLOC_STRUCT(st_manager); + assert(osmesa->manager); + if (osmesa->manager) { + osmesa->manager->screen = osmesa_create_screen(); + osmesa->manager->get_param = osmesa_st_get_param; + osmesa->manager->get_egl_image = NULL; + } + + osmesa->stctx = osmesa->api->create_context(osmesa->api, osmesa->manager, &attribs, &st_error, st_shared); if (!osmesa->stctx) { + FREE(osmesa->manager); + osmesa->api->destroy(osmesa->api); + osmesa->stctx->destroy(osmesa->stctx); FREE(osmesa); return NULL; } @@ -712,7 +660,10 @@ OSMesaDestroyContext(OSMesaContext osmesa) { if (osmesa) { + osmesa_destroy_buffer(osmesa->current_buffer); pp_free(osmesa->pp); + FREE(osmesa->manager); + osmesa->api->destroy(osmesa->api); osmesa->stctx->destroy(osmesa->stctx); FREE(osmesa); } @@ -745,14 +696,26 @@ OSMesaMakeCurrent(OSMesaContext osmesa, void *buffer, GLenum type, GLsizei width, GLsizei height) { - struct st_api *stapi = get_st_api(); struct osmesa_buffer *osbuffer; enum pipe_format color_format; - if (!osmesa || !buffer || width < 1 || height < 1) { + if (!osmesa) { + /* make sure the active context is not referenced anymore */ + _mesa_make_current(NULL, NULL, NULL); return GL_FALSE; } + if (!buffer || width < 1 || height < 1) { + osmesa->api->make_current(osmesa->api, osmesa->stctx, NULL, NULL); + /* make sure the active buffer is not referenced anymore */ + if (osmesa->current_buffer) { + osmesa_destroy_buffer(osmesa->current_buffer); + osmesa->current_buffer = NULL; + } + osmesa->type = 0; + return GL_TRUE; + } + if (osmesa->format == OSMESA_RGB_565 && type != GL_UNSIGNED_SHORT_5_6_5) { return GL_FALSE; } @@ -763,28 +726,43 @@ return GL_FALSE; } - /* See if we already have a buffer that uses these pixel formats */ - osbuffer = osmesa_find_buffer(color_format, - osmesa->depth_stencil_format, - osmesa->accum_format, width, height); - if (!osbuffer) { - /* Existing buffer found, create new buffer */ + osbuffer = osmesa->current_buffer; + /* Try to reuse the osbuffer. */ + if (!(osbuffer && + osbuffer->visual.color_format == color_format && + osbuffer->visual.depth_stencil_format == osmesa->depth_stencil_format && + osbuffer->visual.accum_format == osmesa->accum_format && + osbuffer->width == width && + osbuffer->height == height)) { + if (osbuffer) { + osmesa_destroy_buffer(osbuffer); + } + /* create new buffer */ osbuffer = osmesa_create_buffer(color_format, osmesa->depth_stencil_format, osmesa->accum_format); + osbuffer->width = width; + osbuffer->height = height; + osmesa->current_buffer = osbuffer; + { + /* st_framebuffer_reuse_or_create() uses pointer comparison to check + if it can reuse the framebuffer! + Since we are realocating the buffer (osmesa_create_buffer() calls + osmesa_create_st_framebuffer()) just after freing it, we may be + unlucky. We thus prefer invalidating the framebuffer manually. */ + struct st_context *st = (struct st_context *)osmesa->stctx; + st->ctx->WinSysDrawBuffer = NULL; + st->ctx->WinSysReadBuffer = NULL; + } } - osbuffer->width = width; - osbuffer->height = height; osbuffer->map = buffer; - /* XXX unused for now */ - (void) osmesa_destroy_buffer; - - osmesa->current_buffer = osbuffer; osmesa->type = type; - stapi->make_current(stapi, osmesa->stctx, osbuffer->stfb, osbuffer->stfb); + osmesa->api->make_current(osmesa->api, osmesa->stctx, osbuffer->stfb, osbuffer->stfb); + /* front-left buffer should have a valid texture at this point */ + assert(osbuffer->textures[0]); if (!osmesa->ever_used) { /* one-time init, just postprocessing for now */ @@ -817,9 +795,8 @@ GLAPI OSMesaContext GLAPIENTRY OSMesaGetCurrentContext(void) { - struct st_api *stapi = get_st_api(); - struct st_context_iface *st = stapi->get_current(stapi); - return st ? (OSMesaContext) st->st_manager_private : NULL; + struct gl_context *ctx = _mesa_get_current_context(); + return ctx ? (OSMesaContext) ctx->st->iface.st_manager_private : NULL; } @@ -873,7 +850,7 @@ /* fall-through */ case OSMESA_MAX_HEIGHT: { - struct pipe_screen *screen = get_st_manager()->screen; + struct pipe_screen *screen = osmesa->manager->screen; int maxLevels = screen->get_param(screen, PIPE_CAP_MAX_TEXTURE_2D_LEVELS); *value = 1 << (maxLevels - 1); @@ -905,6 +882,11 @@ struct pipe_transfer *transfer = NULL; struct pipe_box box; + assert(res); + if (!res) { + return GL_FALSE; + } + /* * Note: we can't really implement this function with gallium as * we did for swrast. We can't just map the resource and leave it