Path: blob/21.2-virgl/src/gallium/frontends/osmesa/osmesa_bufferless.c
4565 views
/*1* Copyright (c) 2013 Brian Paul All Rights Reserved.2*3* Permission is hereby granted, free of charge, to any person obtaining a4* copy of this software and associated documentation files (the "Software"),5* to deal in the Software without restriction, including without limitation6* the rights to use, copy, modify, merge, publish, distribute, sublicense,7* and/or sell copies of the Software, and to permit persons to whom the8* Software is furnished to do so, subject to the following conditions:9*10* The above copyright notice and this permission notice shall be included11* in all copies or substantial portions of the Software.12*13* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS14* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,15* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL16* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR17* OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,18* ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR19* OTHER DEALINGS IN THE SOFTWARE.20*/212223/*24* Off-Screen rendering into client memory.25* OpenGL gallium frontend for softpipe and llvmpipe.26*27* Notes:28*29* If Gallium is built with LLVM support we use the llvmpipe driver.30* Otherwise we use softpipe. The GALLIUM_DRIVER environment variable31* may be set to "softpipe" or "llvmpipe" to override.32*33* With softpipe we could render directly into the user's buffer by using a34* display target resource. However, softpipe doesn't support "upside-down"35* rendering which would be needed for the OSMESA_Y_UP=TRUE case.36*37* With llvmpipe we could only render directly into the user's buffer when its38* width and height is a multiple of the tile size (64 pixels).39*40* Because of these constraints we always render into ordinary resources then41* copy the results to the user's buffer in the flush_front() function which42* is called when the app calls glFlush/Finish.43*44* In general, the OSMesa interface is pretty ugly and not a good match45* for Gallium. But we're interested in doing the best we can to preserve46* application portability. With a little work we could come up with a47* much nicer, new off-screen Gallium interface...48*/495051#include <stdio.h>52#include <c11/threads.h>53#include "GL/osmesa.h"5455#include "glapi/glapi.h" /* for OSMesaGetProcAddress below */5657#include "pipe/p_context.h"58#include "pipe/p_screen.h"59#include "pipe/p_state.h"6061#include "util/u_atomic.h"62#include "util/u_box.h"63#include "util/u_debug.h"64#include "util/format/u_format.h"65#include "util/u_inlines.h"66#include "util/u_memory.h"6768#include "postprocess/filters.h"69#include "postprocess/postprocess.h"7071#include "frontend/api.h"72#include "state_tracker/st_gl_api.h"73747576extern struct pipe_screen *77osmesa_create_screen(void);78798081struct osmesa_buffer82{83struct st_framebuffer_iface *stfb;84struct st_visual visual;85unsigned width, height;8687struct pipe_resource *textures[ST_ATTACHMENT_COUNT];8889void *map;9091struct osmesa_buffer *next; /**< next in linked list */92};939495struct osmesa_context96{97struct st_context_iface *stctx;9899boolean ever_used; /*< Has this context ever been current? */100101struct osmesa_buffer *current_buffer;102103/* Storage for depth/stencil, if the user has requested access. The backing104* driver always has its own storage for the actual depth/stencil, which we105* have to transfer in and out.106*/107void *zs;108unsigned zs_stride;109110enum pipe_format depth_stencil_format, accum_format;111112GLenum format; /*< User-specified context format */113GLenum type; /*< Buffer's data type */114GLint user_row_length; /*< user-specified number of pixels per row */115GLboolean y_up; /*< TRUE -> Y increases upward */116/*< FALSE -> Y increases downward */117118/** Which postprocessing filters are enabled. */119unsigned pp_enabled[PP_FILTERS];120struct pp_queue_t *pp;121};122123/**124* Called from the ST manager.125*/126static int127osmesa_st_get_param(struct st_manager *smapi, enum st_manager_param param)128{129/* no-op */130return 0;131}132133static struct st_manager *stmgr = NULL;134static struct st_api *stapi = NULL;135136static void137destroy_st_manager(void)138{139if (stmgr) {140if (stmgr->screen)141stmgr->screen->destroy(stmgr->screen);142FREE(stmgr);143}144145if (stapi && stapi->destroy) {146stapi->destroy(stapi);147}148}149150static void151create_st_manager(void)152{153if (atexit(destroy_st_manager) != 0)154return;155156stmgr = CALLOC_STRUCT(st_manager);157if (stmgr) {158stmgr->screen = osmesa_create_screen();159stmgr->get_param = osmesa_st_get_param;160stmgr->get_egl_image = NULL;161}162163stapi = st_gl_api_create();164debug_printf("OSMESA: stmgr=%p; stapi=%p\n",stmgr,stapi);165}166167/**168* Create/return a singleton st_manager object.169*/170static struct st_manager *171get_st_manager(void)172{173static once_flag create_once_flag = ONCE_FLAG_INIT;174175call_once(&create_once_flag, create_st_manager);176177return stmgr;178}179180/**181* Create/return singleton st_api object.182*/183static struct st_api *184get_st_api(void)185{186get_st_manager();187return stapi;188}189190/* Reads the color or depth buffer from the backing context to either the user storage191* (color buffer) or our temporary (z/s)192*/193static void194osmesa_read_buffer(OSMesaContext osmesa, struct pipe_resource *res, void *dst,195int dst_stride, bool y_up)196{197struct pipe_context *pipe = osmesa->stctx->pipe;198199struct pipe_box box;200u_box_2d(0, 0, res->width0, res->height0, &box);201202struct pipe_transfer *transfer = NULL;203ubyte *src = pipe->texture_map(pipe, res, 0, PIPE_MAP_READ, &box,204&transfer);205206/*207* Copy the color buffer from the resource to the user's buffer.208*/209210if (y_up) {211/* need to flip image upside down */212dst = (ubyte *)dst + (res->height0 - 1) * dst_stride;213dst_stride = -dst_stride;214}215216unsigned bpp = util_format_get_blocksize(res->format);217for (unsigned y = 0; y < res->height0; y++)218{219memcpy(dst, src, bpp * res->width0);220dst = (ubyte *)dst + dst_stride;221src += transfer->stride;222}223224pipe->texture_unmap(pipe, transfer);225}226227228/**229* Given an OSMESA_x format and a GL_y type, return the best230* matching PIPE_FORMAT_z.231* Note that we can't exactly match all user format/type combinations232* with gallium formats. If we find this to be a problem, we can233* implement more elaborate format/type conversion in the flush_front()234* function.235*/236static enum pipe_format237osmesa_choose_format(GLenum format, GLenum type)238{239switch (format) {240case OSMESA_RGBA:241if (type == GL_UNSIGNED_BYTE) {242#if UTIL_ARCH_LITTLE_ENDIAN243return PIPE_FORMAT_R8G8B8A8_UNORM;244#else245return PIPE_FORMAT_A8B8G8R8_UNORM;246#endif247}248else if (type == GL_UNSIGNED_SHORT) {249return PIPE_FORMAT_R16G16B16A16_UNORM;250}251else if (type == GL_FLOAT) {252return PIPE_FORMAT_R32G32B32A32_FLOAT;253}254else {255return PIPE_FORMAT_NONE;256}257break;258case OSMESA_BGRA:259if (type == GL_UNSIGNED_BYTE) {260#if UTIL_ARCH_LITTLE_ENDIAN261return PIPE_FORMAT_B8G8R8A8_UNORM;262#else263return PIPE_FORMAT_A8R8G8B8_UNORM;264#endif265}266else if (type == GL_UNSIGNED_SHORT) {267return PIPE_FORMAT_R16G16B16A16_UNORM;268}269else if (type == GL_FLOAT) {270return PIPE_FORMAT_R32G32B32A32_FLOAT;271}272else {273return PIPE_FORMAT_NONE;274}275break;276case OSMESA_ARGB:277if (type == GL_UNSIGNED_BYTE) {278#if UTIL_ARCH_LITTLE_ENDIAN279return PIPE_FORMAT_A8R8G8B8_UNORM;280#else281return PIPE_FORMAT_B8G8R8A8_UNORM;282#endif283}284else if (type == GL_UNSIGNED_SHORT) {285return PIPE_FORMAT_R16G16B16A16_UNORM;286}287else if (type == GL_FLOAT) {288return PIPE_FORMAT_R32G32B32A32_FLOAT;289}290else {291return PIPE_FORMAT_NONE;292}293break;294case OSMESA_RGB:295if (type == GL_UNSIGNED_BYTE) {296return PIPE_FORMAT_R8G8B8_UNORM;297}298else if (type == GL_UNSIGNED_SHORT) {299return PIPE_FORMAT_R16G16B16_UNORM;300}301else if (type == GL_FLOAT) {302return PIPE_FORMAT_R32G32B32_FLOAT;303}304else {305return PIPE_FORMAT_NONE;306}307break;308case OSMESA_BGR:309/* No gallium format for this one */310return PIPE_FORMAT_NONE;311case OSMESA_RGB_565:312if (type != GL_UNSIGNED_SHORT_5_6_5)313return PIPE_FORMAT_NONE;314return PIPE_FORMAT_B5G6R5_UNORM;315default:316return PIPE_FORMAT_NONE;317}318}319320321/**322* Initialize an st_visual object.323*/324static void325osmesa_init_st_visual(struct st_visual *vis,326enum pipe_format color_format,327enum pipe_format ds_format,328enum pipe_format accum_format)329{330vis->buffer_mask = ST_ATTACHMENT_FRONT_LEFT_MASK;331332if (ds_format != PIPE_FORMAT_NONE)333vis->buffer_mask |= ST_ATTACHMENT_DEPTH_STENCIL_MASK;334if (accum_format != PIPE_FORMAT_NONE)335vis->buffer_mask |= ST_ATTACHMENT_ACCUM;336337vis->color_format = color_format;338vis->depth_stencil_format = ds_format;339vis->accum_format = accum_format;340vis->samples = 1;341}342343344/**345* Return the osmesa_buffer that corresponds to an st_framebuffer_iface.346*/347static inline struct osmesa_buffer *348stfbi_to_osbuffer(struct st_framebuffer_iface *stfbi)349{350return (struct osmesa_buffer *) stfbi->st_manager_private;351}352353354/**355* Called via glFlush/glFinish. This is where we copy the contents356* of the driver's color buffer into the user-specified buffer.357*/358static bool359osmesa_st_framebuffer_flush_front(struct st_context_iface *stctx,360struct st_framebuffer_iface *stfbi,361enum st_attachment_type statt)362{363OSMesaContext osmesa = OSMesaGetCurrentContext();364struct osmesa_buffer *osbuffer = stfbi_to_osbuffer(stfbi);365struct pipe_resource *res = osbuffer->textures[statt];366unsigned bpp;367int dst_stride;368369if (statt != ST_ATTACHMENT_FRONT_LEFT)370return false;371372if (osmesa->pp) {373struct pipe_resource *zsbuf = NULL;374unsigned i;375376/* Find the z/stencil buffer if there is one */377for (i = 0; i < ARRAY_SIZE(osbuffer->textures); i++) {378struct pipe_resource *res = osbuffer->textures[i];379if (res) {380const struct util_format_description *desc =381util_format_description(res->format);382383if (util_format_has_depth(desc)) {384zsbuf = res;385break;386}387}388}389390/* run the postprocess stage(s) */391pp_run(osmesa->pp, res, res, zsbuf);392}393394/* Snapshot the color buffer to the user's buffer. */395bpp = util_format_get_blocksize(osbuffer->visual.color_format);396if (osmesa->user_row_length)397dst_stride = bpp * osmesa->user_row_length;398else399dst_stride = bpp * osbuffer->width;400401// osmesa_read_buffer(osmesa, res, osbuffer->map, dst_stride, osmesa->y_up);402403/* If the user has requested the Z/S buffer, then snapshot that one too. */404// if (osmesa->zs) {405// osmesa_read_buffer(osmesa, osbuffer->textures[ST_ATTACHMENT_DEPTH_STENCIL],406// osmesa->zs, osmesa->zs_stride, true);407// }408409return true;410}411412413/**414* Called by the st manager to validate the framebuffer (allocate415* its resources).416*/417static bool418osmesa_st_framebuffer_validate(struct st_context_iface *stctx,419struct st_framebuffer_iface *stfbi,420const enum st_attachment_type *statts,421unsigned count,422struct pipe_resource **out)423{424struct pipe_screen *screen = get_st_manager()->screen;425enum st_attachment_type i;426struct osmesa_buffer *osbuffer = stfbi_to_osbuffer(stfbi);427struct pipe_resource templat;428429memset(&templat, 0, sizeof(templat));430templat.target = PIPE_TEXTURE_RECT;431templat.format = 0; /* setup below */432templat.last_level = 0;433templat.width0 = osbuffer->width;434templat.height0 = osbuffer->height;435templat.depth0 = 1;436templat.array_size = 1;437templat.usage = PIPE_USAGE_DEFAULT;438templat.bind = 0; /* setup below */439templat.flags = 0;440441for (i = 0; i < count; i++) {442enum pipe_format format = PIPE_FORMAT_NONE;443unsigned bind = 0;444445/*446* At this time, we really only need to handle the front-left color447* attachment, since that's all we specified for the visual in448* osmesa_init_st_visual().449*/450if (statts[i] == ST_ATTACHMENT_FRONT_LEFT) {451format = osbuffer->visual.color_format;452bind = PIPE_BIND_RENDER_TARGET;453}454else if (statts[i] == ST_ATTACHMENT_DEPTH_STENCIL) {455format = osbuffer->visual.depth_stencil_format;456bind = PIPE_BIND_DEPTH_STENCIL;457}458else if (statts[i] == ST_ATTACHMENT_ACCUM) {459format = osbuffer->visual.accum_format;460bind = PIPE_BIND_RENDER_TARGET;461}462else {463debug_warning("Unexpected attachment type in "464"osmesa_st_framebuffer_validate()");465}466467templat.format = format;468templat.bind = bind;469pipe_resource_reference(&out[i], NULL);470out[i] = osbuffer->textures[statts[i]] =471screen->resource_create(screen, &templat);472}473474return true;475}476477static uint32_t osmesa_fb_ID = 0;478479static struct st_framebuffer_iface *480osmesa_create_st_framebuffer(void)481{482struct st_framebuffer_iface *stfbi = CALLOC_STRUCT(st_framebuffer_iface);483if (stfbi) {484stfbi->flush_front = osmesa_st_framebuffer_flush_front;485stfbi->validate = osmesa_st_framebuffer_validate;486p_atomic_set(&stfbi->stamp, 1);487stfbi->ID = p_atomic_inc_return(&osmesa_fb_ID);488stfbi->state_manager = get_st_manager();489}490return stfbi;491}492493494/**495* Create new buffer and add to linked list.496*/497static struct osmesa_buffer *498osmesa_create_buffer(enum pipe_format color_format,499enum pipe_format ds_format,500enum pipe_format accum_format)501{502struct osmesa_buffer *osbuffer = CALLOC_STRUCT(osmesa_buffer);503if (osbuffer) {504osbuffer->stfb = osmesa_create_st_framebuffer();505506osbuffer->stfb->st_manager_private = osbuffer;507osbuffer->stfb->visual = &osbuffer->visual;508509osmesa_init_st_visual(&osbuffer->visual, color_format,510ds_format, accum_format);511}512513return osbuffer;514}515516517static void518osmesa_destroy_buffer(struct osmesa_buffer *osbuffer)519{520/*521* Notify the state manager that the associated framebuffer interface522* is no longer valid.523*/524stapi->destroy_drawable(stapi, osbuffer->stfb);525526FREE(osbuffer->stfb);527FREE(osbuffer);528}529530531532/**********************************************************************/533/***** Public Functions *****/534/**********************************************************************/535536537/**538* Create an Off-Screen Mesa rendering context. The only attribute needed is539* an RGBA vs Color-Index mode flag.540*541* Input: format - Must be GL_RGBA542* sharelist - specifies another OSMesaContext with which to share543* display lists. NULL indicates no sharing.544* Return: an OSMesaContext or 0 if error545*/546GLAPI OSMesaContext GLAPIENTRY547OSMesaCreateContext(GLenum format, OSMesaContext sharelist)548{549return OSMesaCreateContextExt(format, 24, 8, 0, sharelist);550}551552553/**554* New in Mesa 3.5555*556* Create context and specify size of ancillary buffers.557*/558GLAPI OSMesaContext GLAPIENTRY559OSMesaCreateContextExt(GLenum format, GLint depthBits, GLint stencilBits,560GLint accumBits, OSMesaContext sharelist)561{562int attribs[100], n = 0;563564attribs[n++] = OSMESA_FORMAT;565attribs[n++] = format;566attribs[n++] = OSMESA_DEPTH_BITS;567attribs[n++] = depthBits;568attribs[n++] = OSMESA_STENCIL_BITS;569attribs[n++] = stencilBits;570attribs[n++] = OSMESA_ACCUM_BITS;571attribs[n++] = accumBits;572attribs[n++] = 0;573574return OSMesaCreateContextAttribs(attribs, sharelist);575}576577578/**579* New in Mesa 11.2580*581* Create context with attribute list.582*/583GLAPI OSMesaContext GLAPIENTRY584OSMesaCreateContextAttribs(const int *attribList, OSMesaContext sharelist)585{586OSMesaContext osmesa;587struct st_context_iface *st_shared;588enum st_context_error st_error = 0;589struct st_context_attribs attribs;590struct st_api *stapi = get_st_api();591GLenum format = GL_RGBA;592int depthBits = 0, stencilBits = 0, accumBits = 0;593int profile = OSMESA_COMPAT_PROFILE, version_major = 1, version_minor = 0;594int i;595596if (sharelist) {597st_shared = sharelist->stctx;598}599else {600st_shared = NULL;601}602603for (i = 0; attribList[i]; i += 2) {604switch (attribList[i]) {605case OSMESA_FORMAT:606format = attribList[i+1];607switch (format) {608case OSMESA_COLOR_INDEX:609case OSMESA_RGBA:610case OSMESA_BGRA:611case OSMESA_ARGB:612case OSMESA_RGB:613case OSMESA_BGR:614case OSMESA_RGB_565:615/* legal */616break;617default:618return NULL;619}620break;621case OSMESA_DEPTH_BITS:622depthBits = attribList[i+1];623if (depthBits < 0)624return NULL;625break;626case OSMESA_STENCIL_BITS:627stencilBits = attribList[i+1];628if (stencilBits < 0)629return NULL;630break;631case OSMESA_ACCUM_BITS:632accumBits = attribList[i+1];633if (accumBits < 0)634return NULL;635break;636case OSMESA_PROFILE:637profile = attribList[i+1];638if (profile != OSMESA_CORE_PROFILE &&639profile != OSMESA_COMPAT_PROFILE)640return NULL;641break;642case OSMESA_CONTEXT_MAJOR_VERSION:643version_major = attribList[i+1];644if (version_major < 1)645return NULL;646break;647case OSMESA_CONTEXT_MINOR_VERSION:648version_minor = attribList[i+1];649if (version_minor < 0)650return NULL;651break;652case 0:653/* end of list */654break;655default:656fprintf(stderr, "Bad attribute in OSMesaCreateContextAttribs()\n");657return NULL;658}659}660661osmesa = (OSMesaContext) CALLOC_STRUCT(osmesa_context);662if (!osmesa)663return NULL;664665/* Choose depth/stencil/accum buffer formats */666if (accumBits > 0) {667osmesa->accum_format = PIPE_FORMAT_R16G16B16A16_SNORM;668}669if (depthBits > 0 && stencilBits > 0) {670osmesa->depth_stencil_format = PIPE_FORMAT_Z24_UNORM_S8_UINT;671}672else if (stencilBits > 0) {673osmesa->depth_stencil_format = PIPE_FORMAT_S8_UINT;674}675else if (depthBits >= 24) {676osmesa->depth_stencil_format = PIPE_FORMAT_Z24X8_UNORM;677}678else if (depthBits >= 16) {679osmesa->depth_stencil_format = PIPE_FORMAT_Z16_UNORM;680}681682/*683* Create the rendering context684*/685memset(&attribs, 0, sizeof(attribs));686attribs.profile = (profile == OSMESA_CORE_PROFILE)687? ST_PROFILE_OPENGL_CORE : ST_PROFILE_DEFAULT;688attribs.major = version_major;689attribs.minor = version_minor;690attribs.flags = 0; /* ST_CONTEXT_FLAG_x */691attribs.options.force_glsl_extensions_warn = FALSE;692attribs.options.disable_blend_func_extended = FALSE;693attribs.options.disable_glsl_line_continuations = FALSE;694attribs.options.force_glsl_version = 0;695696osmesa_init_st_visual(&attribs.visual,697PIPE_FORMAT_NONE,698osmesa->depth_stencil_format,699osmesa->accum_format);700701osmesa->stctx = stapi->create_context(stapi, get_st_manager(),702&attribs, &st_error, st_shared);703if (!osmesa->stctx) {704char* st_error_str;705switch (st_error) {706case ST_CONTEXT_ERROR_NO_MEMORY:707st_error_str="ST_CONTEXT_ERROR_NO_MEMORY";708break;709case ST_CONTEXT_ERROR_BAD_API:710st_error_str="ST_CONTEXT_ERROR_BAD_API";711break;712case ST_CONTEXT_ERROR_BAD_VERSION:713st_error_str="ST_CONTEXT_ERROR_BAD_VERSION";714break;715case ST_CONTEXT_ERROR_BAD_FLAG:716st_error_str="ST_CONTEXT_ERROR_BAD_FLAG";717break;718case ST_CONTEXT_ERROR_UNKNOWN_ATTRIBUTE:719st_error_str="ST_CONTEXT_ERROR_UNKNOWN_ATTRIBUTE";720break;721case ST_CONTEXT_ERROR_UNKNOWN_FLAG:722st_error_str="ST_CONTEXT_ERROR_UNKNOWN_FLAG";723break;724default:725st_error_str="UNKNOWN";726break;727}728debug_printf("OSMESA: error: unable to create st context, st_error=%s",st_error_str);729FREE(osmesa);730return NULL;731}732733osmesa->stctx->st_manager_private = osmesa;734735osmesa->format = format;736osmesa->user_row_length = 0;737osmesa->y_up = GL_TRUE;738739return osmesa;740}741742743744/**745* Destroy an Off-Screen Mesa rendering context.746*747* \param osmesa the context to destroy748*/749GLAPI void GLAPIENTRY750OSMesaDestroyContext(OSMesaContext osmesa)751{752if (osmesa) {753pp_free(osmesa->pp);754osmesa->stctx->destroy(osmesa->stctx);755free(osmesa->zs);756FREE(osmesa);757}758}759760761/**762* Bind an OSMesaContext to an image buffer. The image buffer is just a763* block of memory which the client provides. Its size must be at least764* as large as width*height*pixelSize. Its address should be a multiple765* of 4 if using RGBA mode.766*767* By default, image data is stored in the order of glDrawPixels: row-major768* order with the lower-left image pixel stored in the first array position769* (ie. bottom-to-top).770*771* If the context's viewport hasn't been initialized yet, it will now be772* initialized to (0,0,width,height).773*774* Input: osmesa - the rendering context775* buffer - the image buffer memory776* type - data type for pixel components777* GL_UNSIGNED_BYTE, GL_UNSIGNED_SHORT_5_6_5, GL_UNSIGNED_SHORT778* or GL_FLOAT.779* width, height - size of image buffer in pixels, at least 1780* Return: GL_TRUE if success, GL_FALSE if error because of invalid osmesa,781* invalid type, invalid size, etc.782*/783GLAPI GLboolean GLAPIENTRY784OSMesaMakeCurrent(OSMesaContext osmesa, void *buffer, GLenum type,785GLsizei width, GLsizei height)786{787struct st_api *stapi = get_st_api();788enum pipe_format color_format;789790if (!osmesa && !buffer) {791stapi->make_current(stapi, NULL, NULL, NULL);792return GL_TRUE;793}794795if (!osmesa || !buffer || width < 1 || height < 1) {796return GL_FALSE;797}798799color_format = osmesa_choose_format(osmesa->format, type);800if (color_format == PIPE_FORMAT_NONE) {801fprintf(stderr, "OSMesaMakeCurrent(unsupported format/type)\n");802return GL_FALSE;803}804805/* See if we already have a buffer that uses these pixel formats */806if (osmesa->current_buffer &&807(osmesa->current_buffer->visual.color_format != color_format ||808osmesa->current_buffer->visual.depth_stencil_format != osmesa->depth_stencil_format ||809osmesa->current_buffer->visual.accum_format != osmesa->accum_format)) {810osmesa_destroy_buffer(osmesa->current_buffer);811}812813if (!osmesa->current_buffer) {814osmesa->current_buffer = osmesa_create_buffer(color_format,815osmesa->depth_stencil_format,816osmesa->accum_format);817}818819struct osmesa_buffer *osbuffer = osmesa->current_buffer;820821osbuffer->width = width;822osbuffer->height = height;823osbuffer->map = buffer;824825osmesa->type = type;826827stapi->make_current(stapi, osmesa->stctx, osbuffer->stfb, osbuffer->stfb);828829/* XXX: We should probably load the current color value into the buffer here830* to match classic swrast behavior (context's fb starts with the contents of831* your pixel buffer).832*/833834if (!osmesa->ever_used) {835/* one-time init, just postprocessing for now */836boolean any_pp_enabled = FALSE;837unsigned i;838839for (i = 0; i < ARRAY_SIZE(osmesa->pp_enabled); i++) {840if (osmesa->pp_enabled[i]) {841any_pp_enabled = TRUE;842break;843}844}845846if (any_pp_enabled) {847osmesa->pp = pp_init(osmesa->stctx->pipe,848osmesa->pp_enabled,849osmesa->stctx->cso_context,850osmesa->stctx);851852pp_init_fbos(osmesa->pp, width, height);853}854855osmesa->ever_used = TRUE;856}857858return GL_TRUE;859}860861862863GLAPI OSMesaContext GLAPIENTRY864OSMesaGetCurrentContext(void)865{866struct st_api *stapi = get_st_api();867struct st_context_iface *st = stapi->get_current(stapi);868return st ? (OSMesaContext) st->st_manager_private : NULL;869}870871872873GLAPI void GLAPIENTRY874OSMesaPixelStore(GLint pname, GLint value)875{876OSMesaContext osmesa = OSMesaGetCurrentContext();877878switch (pname) {879case OSMESA_ROW_LENGTH:880osmesa->user_row_length = value;881break;882case OSMESA_Y_UP:883osmesa->y_up = value ? GL_TRUE : GL_FALSE;884break;885default:886fprintf(stderr, "Invalid pname in OSMesaPixelStore()\n");887return;888}889}890891892GLAPI void GLAPIENTRY893OSMesaGetIntegerv(GLint pname, GLint *value)894{895OSMesaContext osmesa = OSMesaGetCurrentContext();896struct osmesa_buffer *osbuffer = osmesa ? osmesa->current_buffer : NULL;897898switch (pname) {899case OSMESA_WIDTH:900*value = osbuffer ? osbuffer->width : 0;901return;902case OSMESA_HEIGHT:903*value = osbuffer ? osbuffer->height : 0;904return;905case OSMESA_FORMAT:906*value = osmesa->format;907return;908case OSMESA_TYPE:909/* current color buffer's data type */910*value = osmesa->type;911return;912case OSMESA_ROW_LENGTH:913*value = osmesa->user_row_length;914return;915case OSMESA_Y_UP:916*value = osmesa->y_up;917return;918case OSMESA_MAX_WIDTH:919FALLTHROUGH;920case OSMESA_MAX_HEIGHT:921{922struct pipe_screen *screen = get_st_manager()->screen;923*value = screen->get_param(screen, PIPE_CAP_MAX_TEXTURE_2D_SIZE);924}925return;926default:927fprintf(stderr, "Invalid pname in OSMesaGetIntegerv()\n");928return;929}930}931932933/**934* Return information about the depth buffer associated with an OSMesa context.935* Input: c - the OSMesa context936* Output: width, height - size of buffer in pixels937* bytesPerValue - bytes per depth value (2 or 4)938* buffer - pointer to depth buffer values939* Return: GL_TRUE or GL_FALSE to indicate success or failure.940*/941GLAPI GLboolean GLAPIENTRY942OSMesaGetDepthBuffer(OSMesaContext c, GLint *width, GLint *height,943GLint *bytesPerValue, void **buffer)944{945struct osmesa_buffer *osbuffer = c->current_buffer;946struct pipe_resource *res = osbuffer->textures[ST_ATTACHMENT_DEPTH_STENCIL];947948if (!res) {949*width = 0;950*height = 0;951*bytesPerValue = 0;952*buffer = NULL;953return GL_FALSE;954}955956*width = res->width0;957*height = res->height0;958*bytesPerValue = util_format_get_blocksize(res->format);959960if (!c->zs) {961c->zs_stride = *width * *bytesPerValue;962c->zs = calloc(c->zs_stride, *height);963if (!c->zs)964return GL_FALSE;965966osmesa_read_buffer(c, res, c->zs, c->zs_stride, true);967}968969*buffer = c->zs;970971return GL_TRUE;972}973974975/**976* Return the color buffer associated with an OSMesa context.977* Input: c - the OSMesa context978* Output: width, height - size of buffer in pixels979* format - the pixel format (OSMESA_FORMAT)980* buffer - pointer to color buffer values981* Return: GL_TRUE or GL_FALSE to indicate success or failure.982*/983GLAPI GLboolean GLAPIENTRY984OSMesaGetColorBuffer(OSMesaContext osmesa, GLint *width,985GLint *height, GLint *format, void **buffer)986{987struct osmesa_buffer *osbuffer = osmesa->current_buffer;988989if (osbuffer) {990*width = osbuffer->width;991*height = osbuffer->height;992*format = osmesa->format;993*buffer = osbuffer->map;994return GL_TRUE;995}996else {997*width = 0;998*height = 0;999*format = 0;1000*buffer = 0;1001return GL_FALSE;1002}1003}100410051006struct name_function1007{1008const char *Name;1009OSMESAproc Function;1010};10111012static struct name_function functions[] = {1013{ "OSMesaCreateContext", (OSMESAproc) OSMesaCreateContext },1014{ "OSMesaCreateContextExt", (OSMESAproc) OSMesaCreateContextExt },1015{ "OSMesaCreateContextAttribs", (OSMESAproc) OSMesaCreateContextAttribs },1016{ "OSMesaDestroyContext", (OSMESAproc) OSMesaDestroyContext },1017{ "OSMesaMakeCurrent", (OSMESAproc) OSMesaMakeCurrent },1018{ "OSMesaGetCurrentContext", (OSMESAproc) OSMesaGetCurrentContext },1019{ "OSMesaPixelStore", (OSMESAproc) OSMesaPixelStore },1020{ "OSMesaGetIntegerv", (OSMESAproc) OSMesaGetIntegerv },1021{ "OSMesaGetDepthBuffer", (OSMESAproc) OSMesaGetDepthBuffer },1022{ "OSMesaGetColorBuffer", (OSMESAproc) OSMesaGetColorBuffer },1023{ "OSMesaGetProcAddress", (OSMESAproc) OSMesaGetProcAddress },1024{ "OSMesaColorClamp", (OSMESAproc) OSMesaColorClamp },1025{ "OSMesaPostprocess", (OSMESAproc) OSMesaPostprocess },1026{ NULL, NULL }1027};102810291030GLAPI OSMESAproc GLAPIENTRY1031OSMesaGetProcAddress(const char *funcName)1032{1033int i;1034for (i = 0; functions[i].Name; i++) {1035if (strcmp(functions[i].Name, funcName) == 0)1036return functions[i].Function;1037}1038return _glapi_get_proc_address(funcName);1039}104010411042GLAPI void GLAPIENTRY1043OSMesaColorClamp(GLboolean enable)1044{1045extern void GLAPIENTRY _mesa_ClampColor(GLenum target, GLenum clamp);10461047_mesa_ClampColor(GL_CLAMP_FRAGMENT_COLOR_ARB,1048enable ? GL_TRUE : GL_FIXED_ONLY_ARB);1049}105010511052GLAPI void GLAPIENTRY1053OSMesaPostprocess(OSMesaContext osmesa, const char *filter,1054unsigned enable_value)1055{1056if (!osmesa->ever_used) {1057/* We can only enable/disable postprocess filters before a context1058* is made current for the first time.1059*/1060unsigned i;10611062for (i = 0; i < PP_FILTERS; i++) {1063if (strcmp(pp_filters[i].name, filter) == 0) {1064osmesa->pp_enabled[i] = enable_value;1065return;1066}1067}1068debug_warning("OSMesaPostprocess(unknown filter)\n");1069}1070else {1071debug_warning("Calling OSMesaPostprocess() after OSMesaMakeCurrent()\n");1072}1073}107410751076