Path: blob/21.2-virgl/src/gallium/frontends/dri/dri_drawable.c
4565 views
/**************************************************************************1*2* Copyright 2009, VMware, Inc.3* All Rights Reserved.4*5* Permission is hereby granted, free of charge, to any person obtaining a6* copy of this software and associated documentation files (the7* "Software"), to deal in the Software without restriction, including8* without limitation the rights to use, copy, modify, merge, publish,9* distribute, sub license, and/or sell copies of the Software, and to10* permit persons to whom the Software is furnished to do so, subject to11* the following conditions:12*13* The above copyright notice and this permission notice (including the14* next paragraph) shall be included in all copies or substantial portions15* of the Software.16*17* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS18* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF19* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT.20* IN NO EVENT SHALL VMWARE AND/OR ITS SUPPLIERS BE LIABLE FOR21* ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,22* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE23* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.24*25**************************************************************************/26/*27* Author: Keith Whitwell <[email protected]>28* Author: Jakob Bornecrantz <[email protected]>29*/3031#include "dri_screen.h"32#include "dri_context.h"33#include "dri_drawable.h"3435#include "pipe/p_screen.h"36#include "util/format/u_format.h"37#include "util/u_memory.h"38#include "util/u_inlines.h"3940static uint32_t drifb_ID = 0;4142static bool43dri_st_framebuffer_validate(struct st_context_iface *stctx,44struct st_framebuffer_iface *stfbi,45const enum st_attachment_type *statts,46unsigned count,47struct pipe_resource **out)48{49struct dri_context *ctx = (struct dri_context *)stctx->st_manager_private;50struct dri_drawable *drawable =51(struct dri_drawable *) stfbi->st_manager_private;52struct dri_screen *screen = dri_screen(drawable->sPriv);53unsigned statt_mask, new_mask;54bool new_stamp;55int i;56unsigned int lastStamp;57struct pipe_resource **textures =58drawable->stvis.samples > 1 ? drawable->msaa_textures59: drawable->textures;6061statt_mask = 0x0;62for (i = 0; i < count; i++)63statt_mask |= (1 << statts[i]);6465/* record newly allocated textures */66new_mask = (statt_mask & ~drawable->texture_mask);6768/*69* dPriv->dri2.stamp is the server stamp. dPriv->lastStamp is the70* client stamp. It has the value of the server stamp when last71* checked.72*/73do {74lastStamp = drawable->dPriv->lastStamp;75new_stamp = (drawable->texture_stamp != lastStamp);7677if (new_stamp || new_mask || screen->broken_invalidate) {78if (new_stamp && drawable->update_drawable_info)79drawable->update_drawable_info(drawable);8081drawable->allocate_textures(ctx, drawable, statts, count);8283/* add existing textures */84for (i = 0; i < ST_ATTACHMENT_COUNT; i++) {85if (textures[i])86statt_mask |= (1 << i);87}8889drawable->texture_stamp = lastStamp;90drawable->texture_mask = statt_mask;91}92} while (lastStamp != drawable->dPriv->lastStamp);9394/* Flush the pending set_damage_region request. */95struct pipe_screen *pscreen = screen->base.screen;9697if (new_mask & (1 << ST_ATTACHMENT_BACK_LEFT) &&98pscreen->set_damage_region) {99struct pipe_resource *resource = textures[ST_ATTACHMENT_BACK_LEFT];100101pscreen->set_damage_region(pscreen, resource,102drawable->num_damage_rects,103drawable->damage_rects);104}105106if (!out)107return true;108109/* Set the window-system buffers for the gallium frontend. */110for (i = 0; i < count; i++)111pipe_resource_reference(&out[i], textures[statts[i]]);112113return true;114}115116static bool117dri_st_framebuffer_flush_front(struct st_context_iface *stctx,118struct st_framebuffer_iface *stfbi,119enum st_attachment_type statt)120{121struct dri_context *ctx = (struct dri_context *)stctx->st_manager_private;122struct dri_drawable *drawable =123(struct dri_drawable *) stfbi->st_manager_private;124125/* XXX remove this and just set the correct one on the framebuffer */126return drawable->flush_frontbuffer(ctx, drawable, statt);127}128129/**130* The gallium frontend framebuffer interface flush_swapbuffers callback131*/132static bool133dri_st_framebuffer_flush_swapbuffers(struct st_context_iface *stctx,134struct st_framebuffer_iface *stfbi)135{136struct dri_context *ctx = (struct dri_context *)stctx->st_manager_private;137struct dri_drawable *drawable =138(struct dri_drawable *) stfbi->st_manager_private;139140if (drawable->flush_swapbuffers)141drawable->flush_swapbuffers(ctx, drawable);142143return true;144}145146/**147* This is called when we need to set up GL rendering to a new X window.148*/149bool150dri_create_buffer(__DRIscreen * sPriv,151__DRIdrawable * dPriv,152const struct gl_config * visual, bool isPixmap)153{154struct dri_screen *screen = sPriv->driverPrivate;155struct dri_drawable *drawable = NULL;156157if (isPixmap)158goto fail; /* not implemented */159160drawable = CALLOC_STRUCT(dri_drawable);161if (drawable == NULL)162goto fail;163164dri_fill_st_visual(&drawable->stvis, screen, visual);165166/* setup the st_framebuffer_iface */167drawable->base.visual = &drawable->stvis;168drawable->base.flush_front = dri_st_framebuffer_flush_front;169drawable->base.validate = dri_st_framebuffer_validate;170drawable->base.flush_swapbuffers = dri_st_framebuffer_flush_swapbuffers;171drawable->base.st_manager_private = (void *) drawable;172173drawable->screen = screen;174drawable->sPriv = sPriv;175drawable->dPriv = dPriv;176177dPriv->driverPrivate = (void *)drawable;178p_atomic_set(&drawable->base.stamp, 1);179drawable->base.ID = p_atomic_inc_return(&drifb_ID);180drawable->base.state_manager = &screen->base;181182return true;183fail:184FREE(drawable);185return false;186}187188void189dri_destroy_buffer(__DRIdrawable * dPriv)190{191struct dri_drawable *drawable = dri_drawable(dPriv);192struct dri_screen *screen = drawable->screen;193struct st_api *stapi = screen->st_api;194int i;195196for (i = 0; i < ST_ATTACHMENT_COUNT; i++)197pipe_resource_reference(&drawable->textures[i], NULL);198for (i = 0; i < ST_ATTACHMENT_COUNT; i++)199pipe_resource_reference(&drawable->msaa_textures[i], NULL);200201screen->base.screen->fence_reference(screen->base.screen,202&drawable->throttle_fence, NULL);203204/* Notify the st manager that this drawable is no longer valid */205stapi->destroy_drawable(stapi, &drawable->base);206207FREE(drawable->damage_rects);208FREE(drawable);209}210211/**212* Validate the texture at an attachment. Allocate the texture if it does not213* exist. Used by the TFP extension.214*/215static void216dri_drawable_validate_att(struct dri_context *ctx,217struct dri_drawable *drawable,218enum st_attachment_type statt)219{220enum st_attachment_type statts[ST_ATTACHMENT_COUNT];221unsigned i, count = 0;222223/* check if buffer already exists */224if (drawable->texture_mask & (1 << statt))225return;226227/* make sure DRI2 does not destroy existing buffers */228for (i = 0; i < ST_ATTACHMENT_COUNT; i++) {229if (drawable->texture_mask & (1 << i)) {230statts[count++] = i;231}232}233statts[count++] = statt;234235drawable->texture_stamp = drawable->dPriv->lastStamp - 1;236237drawable->base.validate(ctx->st, &drawable->base, statts, count, NULL);238}239240/**241* These are used for GLX_EXT_texture_from_pixmap242*/243static void244dri_set_tex_buffer2(__DRIcontext *pDRICtx, GLint target,245GLint format, __DRIdrawable *dPriv)246{247struct dri_context *ctx = dri_context(pDRICtx);248struct st_context_iface *st = ctx->st;249struct dri_drawable *drawable = dri_drawable(dPriv);250struct pipe_resource *pt;251252if (st->thread_finish)253st->thread_finish(st);254255dri_drawable_validate_att(ctx, drawable, ST_ATTACHMENT_FRONT_LEFT);256257/* Use the pipe resource associated with the X drawable */258pt = drawable->textures[ST_ATTACHMENT_FRONT_LEFT];259260if (pt) {261enum pipe_format internal_format = pt->format;262263if (format == __DRI_TEXTURE_FORMAT_RGB) {264/* only need to cover the formats recognized by dri_fill_st_visual */265switch (internal_format) {266case PIPE_FORMAT_R16G16B16A16_FLOAT:267internal_format = PIPE_FORMAT_R16G16B16X16_FLOAT;268break;269case PIPE_FORMAT_B10G10R10A2_UNORM:270internal_format = PIPE_FORMAT_B10G10R10X2_UNORM;271break;272case PIPE_FORMAT_R10G10B10A2_UNORM:273internal_format = PIPE_FORMAT_R10G10B10X2_UNORM;274break;275case PIPE_FORMAT_BGRA8888_UNORM:276internal_format = PIPE_FORMAT_BGRX8888_UNORM;277break;278case PIPE_FORMAT_ARGB8888_UNORM:279internal_format = PIPE_FORMAT_XRGB8888_UNORM;280break;281default:282break;283}284}285286drawable->update_tex_buffer(drawable, ctx, pt);287288ctx->st->teximage(ctx->st,289(target == GL_TEXTURE_2D) ? ST_TEXTURE_2D : ST_TEXTURE_RECT,2900, internal_format, pt, false);291}292}293294static void295dri_set_tex_buffer(__DRIcontext *pDRICtx, GLint target,296__DRIdrawable *dPriv)297{298dri_set_tex_buffer2(pDRICtx, target, __DRI_TEXTURE_FORMAT_RGBA, dPriv);299}300301const __DRItexBufferExtension driTexBufferExtension = {302.base = { __DRI_TEX_BUFFER, 2 },303304.setTexBuffer = dri_set_tex_buffer,305.setTexBuffer2 = dri_set_tex_buffer2,306.releaseTexBuffer = NULL,307};308309/**310* Get the format and binding of an attachment.311*/312void313dri_drawable_get_format(struct dri_drawable *drawable,314enum st_attachment_type statt,315enum pipe_format *format,316unsigned *bind)317{318switch (statt) {319case ST_ATTACHMENT_FRONT_LEFT:320case ST_ATTACHMENT_BACK_LEFT:321case ST_ATTACHMENT_FRONT_RIGHT:322case ST_ATTACHMENT_BACK_RIGHT:323/* Other pieces of the driver stack get confused and behave incorrectly324* when they get an sRGB drawable. st/mesa receives "drawable->stvis"325* though other means and handles it correctly, so we don't really need326* to use an sRGB format here.327*/328*format = util_format_linear(drawable->stvis.color_format);329*bind = PIPE_BIND_RENDER_TARGET | PIPE_BIND_SAMPLER_VIEW;330break;331case ST_ATTACHMENT_DEPTH_STENCIL:332*format = drawable->stvis.depth_stencil_format;333*bind = PIPE_BIND_DEPTH_STENCIL; /* XXX sampler? */334break;335default:336*format = PIPE_FORMAT_NONE;337*bind = 0;338break;339}340}341342void343dri_pipe_blit(struct pipe_context *pipe,344struct pipe_resource *dst,345struct pipe_resource *src)346{347struct pipe_blit_info blit;348349if (!dst || !src)350return;351352/* From the GL spec, version 4.2, section 4.1.11 (Additional Multisample353* Fragment Operations):354*355* If a framebuffer object is not bound, after all operations have356* been completed on the multisample buffer, the sample values for357* each color in the multisample buffer are combined to produce a358* single color value, and that value is written into the359* corresponding color buffers selected by DrawBuffer or360* DrawBuffers. An implementation may defer the writing of the color361* buffers until a later time, but the state of the framebuffer must362* behave as if the color buffers were updated as each fragment was363* processed. The method of combination is not specified. If the364* framebuffer contains sRGB values, then it is recommended that the365* an average of sample values is computed in a linearized space, as366* for blending (see section 4.1.7).367*368* In other words, to do a resolve operation in a linear space, we have369* to set sRGB formats if the original resources were sRGB, so don't use370* util_format_linear.371*/372373memset(&blit, 0, sizeof(blit));374blit.dst.resource = dst;375blit.dst.box.width = dst->width0;376blit.dst.box.height = dst->height0;377blit.dst.box.depth = 1;378blit.dst.format = dst->format;379blit.src.resource = src;380blit.src.box.width = src->width0;381blit.src.box.height = src->height0;382blit.src.box.depth = 1;383blit.src.format = src->format;384blit.mask = PIPE_MASK_RGBA;385blit.filter = PIPE_TEX_FILTER_NEAREST;386387pipe->blit(pipe, &blit);388}389390static void391dri_postprocessing(struct dri_context *ctx,392struct dri_drawable *drawable,393enum st_attachment_type att)394{395struct pipe_resource *src = drawable->textures[att];396struct pipe_resource *zsbuf = drawable->textures[ST_ATTACHMENT_DEPTH_STENCIL];397398if (ctx->pp && src)399pp_run(ctx->pp, src, src, zsbuf);400}401402struct notify_before_flush_cb_args {403struct dri_context *ctx;404struct dri_drawable *drawable;405unsigned flags;406enum __DRI2throttleReason reason;407bool swap_msaa_buffers;408};409410static void411notify_before_flush_cb(void* _args)412{413struct notify_before_flush_cb_args *args = (struct notify_before_flush_cb_args *) _args;414struct st_context_iface *st = args->ctx->st;415struct pipe_context *pipe = st->pipe;416417if (args->drawable->stvis.samples > 1 &&418(args->reason == __DRI2_THROTTLE_SWAPBUFFER ||419args->reason == __DRI2_THROTTLE_COPYSUBBUFFER)) {420/* Resolve the MSAA back buffer. */421dri_pipe_blit(st->pipe,422args->drawable->textures[ST_ATTACHMENT_BACK_LEFT],423args->drawable->msaa_textures[ST_ATTACHMENT_BACK_LEFT]);424425if (args->reason == __DRI2_THROTTLE_SWAPBUFFER &&426args->drawable->msaa_textures[ST_ATTACHMENT_FRONT_LEFT] &&427args->drawable->msaa_textures[ST_ATTACHMENT_BACK_LEFT]) {428args->swap_msaa_buffers = true;429}430431/* FRONT_LEFT is resolved in drawable->flush_frontbuffer. */432}433434dri_postprocessing(args->ctx, args->drawable, ST_ATTACHMENT_BACK_LEFT);435436if (pipe->invalidate_resource &&437(args->flags & __DRI2_FLUSH_INVALIDATE_ANCILLARY)) {438if (args->drawable->textures[ST_ATTACHMENT_DEPTH_STENCIL])439pipe->invalidate_resource(pipe, args->drawable->textures[ST_ATTACHMENT_DEPTH_STENCIL]);440if (args->drawable->msaa_textures[ST_ATTACHMENT_DEPTH_STENCIL])441pipe->invalidate_resource(pipe, args->drawable->msaa_textures[ST_ATTACHMENT_DEPTH_STENCIL]);442}443444if (args->ctx->hud) {445hud_run(args->ctx->hud, args->ctx->st->cso_context,446args->drawable->textures[ST_ATTACHMENT_BACK_LEFT]);447}448449pipe->flush_resource(pipe, args->drawable->textures[ST_ATTACHMENT_BACK_LEFT]);450}451452/**453* DRI2 flush extension, the flush_with_flags function.454*455* \param context the context456* \param drawable the drawable to flush457* \param flags a combination of _DRI2_FLUSH_xxx flags458* \param throttle_reason the reason for throttling, 0 = no throttling459*/460void461dri_flush(__DRIcontext *cPriv,462__DRIdrawable *dPriv,463unsigned flags,464enum __DRI2throttleReason reason)465{466struct dri_context *ctx = dri_context(cPriv);467struct dri_drawable *drawable = dri_drawable(dPriv);468struct st_context_iface *st;469unsigned flush_flags;470struct notify_before_flush_cb_args args = { 0 };471472if (!ctx) {473assert(0);474return;475}476477st = ctx->st;478if (st->thread_finish)479st->thread_finish(st);480481if (drawable) {482/* prevent recursion */483if (drawable->flushing)484return;485486drawable->flushing = true;487}488else {489flags &= ~__DRI2_FLUSH_DRAWABLE;490}491492if ((flags & __DRI2_FLUSH_DRAWABLE) &&493drawable->textures[ST_ATTACHMENT_BACK_LEFT]) {494/* We can't do operations on the back buffer here, because there495* may be some pending operations that will get flushed by the496* call to st->flush (eg: FLUSH_VERTICES).497* Instead we register a callback to be notified when all operations498* have been submitted but before the call to st_flush.499*/500args.ctx = ctx;501args.drawable = drawable;502args.flags = flags;503args.reason = reason;504}505506flush_flags = 0;507if (flags & __DRI2_FLUSH_CONTEXT)508flush_flags |= ST_FLUSH_FRONT;509if (reason == __DRI2_THROTTLE_SWAPBUFFER)510flush_flags |= ST_FLUSH_END_OF_FRAME;511512/* Flush the context and throttle if needed. */513if (dri_screen(ctx->sPriv)->throttle &&514drawable &&515(reason == __DRI2_THROTTLE_SWAPBUFFER ||516reason == __DRI2_THROTTLE_FLUSHFRONT)) {517518struct pipe_screen *screen = drawable->screen->base.screen;519struct pipe_fence_handle *new_fence = NULL;520521st->flush(st, flush_flags, &new_fence, args.ctx ? notify_before_flush_cb : NULL, &args);522523/* throttle on the previous fence */524if (drawable->throttle_fence) {525screen->fence_finish(screen, NULL, drawable->throttle_fence, PIPE_TIMEOUT_INFINITE);526screen->fence_reference(screen, &drawable->throttle_fence, NULL);527}528drawable->throttle_fence = new_fence;529}530else if (flags & (__DRI2_FLUSH_DRAWABLE | __DRI2_FLUSH_CONTEXT)) {531st->flush(st, flush_flags, NULL, args.ctx ? notify_before_flush_cb : NULL, &args);532}533534if (drawable) {535drawable->flushing = false;536}537538/* Swap the MSAA front and back buffers, so that reading539* from the front buffer after SwapBuffers returns what was540* in the back buffer.541*/542if (args.swap_msaa_buffers) {543struct pipe_resource *tmp =544drawable->msaa_textures[ST_ATTACHMENT_FRONT_LEFT];545546drawable->msaa_textures[ST_ATTACHMENT_FRONT_LEFT] =547drawable->msaa_textures[ST_ATTACHMENT_BACK_LEFT];548drawable->msaa_textures[ST_ATTACHMENT_BACK_LEFT] = tmp;549550/* Now that we have swapped the buffers, this tells the gallium551* frontend to revalidate the framebuffer.552*/553p_atomic_inc(&drawable->base.stamp);554}555}556557/**558* dri_throttle - A DRI2ThrottleExtension throttling function.559*/560static void561dri_throttle(__DRIcontext *cPriv, __DRIdrawable *dPriv,562enum __DRI2throttleReason reason)563{564dri_flush(cPriv, dPriv, 0, reason);565}566567568const __DRI2throttleExtension dri2ThrottleExtension = {569.base = { __DRI2_THROTTLE, 1 },570571.throttle = dri_throttle,572};573574575/* vim: set sw=3 ts=8 sts=3 expandtab: */576577578