Path: blob/21.2-virgl/src/gallium/frontends/dri/drisw.c
4565 views
/**************************************************************************1*2* Copyright 2009, VMware, Inc.3* All Rights Reserved.4* Copyright 2010 George Sapountzis <[email protected]>5*6* Permission is hereby granted, free of charge, to any person obtaining a7* copy of this software and associated documentation files (the8* "Software"), to deal in the Software without restriction, including9* without limitation the rights to use, copy, modify, merge, publish,10* distribute, sub license, and/or sell copies of the Software, and to11* permit persons to whom the Software is furnished to do so, subject to12* the following conditions:13*14* The above copyright notice and this permission notice (including the15* next paragraph) shall be included in all copies or substantial portions16* of the Software.17*18* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS19* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF20* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT.21* IN NO EVENT SHALL VMWARE AND/OR ITS SUPPLIERS BE LIABLE FOR22* ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,23* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE24* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.25*26**************************************************************************/2728#include "util/format/u_format.h"29#include "util/u_memory.h"30#include "util/u_inlines.h"31#include "util/u_box.h"32#include "pipe/p_context.h"33#include "pipe-loader/pipe_loader.h"34#include "frontend/drisw_api.h"35#include "state_tracker/st_context.h"3637#include "dri_screen.h"38#include "dri_context.h"39#include "dri_drawable.h"40#include "dri_helpers.h"41#include "dri_query_renderer.h"4243DEBUG_GET_ONCE_BOOL_OPTION(swrast_no_present, "SWRAST_NO_PRESENT", FALSE);4445static inline void46get_drawable_info(__DRIdrawable *dPriv, int *x, int *y, int *w, int *h)47{48__DRIscreen *sPriv = dPriv->driScreenPriv;49const __DRIswrastLoaderExtension *loader = sPriv->swrast_loader;5051loader->getDrawableInfo(dPriv,52x, y, w, h,53dPriv->loaderPrivate);54}5556static inline void57put_image(__DRIdrawable *dPriv, void *data, unsigned width, unsigned height)58{59__DRIscreen *sPriv = dPriv->driScreenPriv;60const __DRIswrastLoaderExtension *loader = sPriv->swrast_loader;6162loader->putImage(dPriv, __DRI_SWRAST_IMAGE_OP_SWAP,630, 0, width, height,64data, dPriv->loaderPrivate);65}6667static inline void68put_image2(__DRIdrawable *dPriv, void *data, int x, int y,69unsigned width, unsigned height, unsigned stride)70{71__DRIscreen *sPriv = dPriv->driScreenPriv;72const __DRIswrastLoaderExtension *loader = sPriv->swrast_loader;7374loader->putImage2(dPriv, __DRI_SWRAST_IMAGE_OP_SWAP,75x, y, width, height, stride,76data, dPriv->loaderPrivate);77}7879static inline void80put_image_shm(__DRIdrawable *dPriv, int shmid, char *shmaddr,81unsigned offset, unsigned offset_x, int x, int y,82unsigned width, unsigned height, unsigned stride)83{84__DRIscreen *sPriv = dPriv->driScreenPriv;85const __DRIswrastLoaderExtension *loader = sPriv->swrast_loader;8687/* if we have the newer interface, don't have to add the offset_x here. */88if (loader->base.version > 4 && loader->putImageShm2)89loader->putImageShm2(dPriv, __DRI_SWRAST_IMAGE_OP_SWAP,90x, y, width, height, stride,91shmid, shmaddr, offset, dPriv->loaderPrivate);92else93loader->putImageShm(dPriv, __DRI_SWRAST_IMAGE_OP_SWAP,94x, y, width, height, stride,95shmid, shmaddr, offset + offset_x, dPriv->loaderPrivate);96}9798static inline void99get_image(__DRIdrawable *dPriv, int x, int y, int width, int height, void *data)100{101__DRIscreen *sPriv = dPriv->driScreenPriv;102const __DRIswrastLoaderExtension *loader = sPriv->swrast_loader;103104loader->getImage(dPriv,105x, y, width, height,106data, dPriv->loaderPrivate);107}108109static inline void110get_image2(__DRIdrawable *dPriv, int x, int y, int width, int height, int stride, void *data)111{112__DRIscreen *sPriv = dPriv->driScreenPriv;113const __DRIswrastLoaderExtension *loader = sPriv->swrast_loader;114115/* getImage2 support is only in version 3 or newer */116if (loader->base.version < 3)117return;118119loader->getImage2(dPriv,120x, y, width, height, stride,121data, dPriv->loaderPrivate);122}123124static inline bool125get_image_shm(__DRIdrawable *dPriv, int x, int y, int width, int height,126struct pipe_resource *res)127{128__DRIscreen *sPriv = dPriv->driScreenPriv;129const __DRIswrastLoaderExtension *loader = sPriv->swrast_loader;130struct winsys_handle whandle;131132whandle.type = WINSYS_HANDLE_TYPE_SHMID;133134if (loader->base.version < 4 || !loader->getImageShm)135return FALSE;136137if (!res->screen->resource_get_handle(res->screen, NULL, res, &whandle, PIPE_HANDLE_USAGE_FRAMEBUFFER_WRITE))138return FALSE;139140if (loader->base.version > 5 && loader->getImageShm2)141return loader->getImageShm2(dPriv, x, y, width, height, whandle.handle, dPriv->loaderPrivate);142143loader->getImageShm(dPriv, x, y, width, height, whandle.handle, dPriv->loaderPrivate);144return TRUE;145}146147static void148drisw_update_drawable_info(struct dri_drawable *drawable)149{150__DRIdrawable *dPriv = drawable->dPriv;151int x, y;152153get_drawable_info(dPriv, &x, &y, &dPriv->w, &dPriv->h);154}155156static void157drisw_get_image(struct dri_drawable *drawable,158int x, int y, unsigned width, unsigned height, unsigned stride,159void *data)160{161__DRIdrawable *dPriv = drawable->dPriv;162int draw_x, draw_y, draw_w, draw_h;163164get_drawable_info(dPriv, &draw_x, &draw_y, &draw_w, &draw_h);165get_image2(dPriv, x, y, draw_w, draw_h, stride, data);166}167168static void169drisw_put_image(struct dri_drawable *drawable,170void *data, unsigned width, unsigned height)171{172__DRIdrawable *dPriv = drawable->dPriv;173174put_image(dPriv, data, width, height);175}176177static void178drisw_put_image2(struct dri_drawable *drawable,179void *data, int x, int y, unsigned width, unsigned height,180unsigned stride)181{182__DRIdrawable *dPriv = drawable->dPriv;183184put_image2(dPriv, data, x, y, width, height, stride);185}186187static inline void188drisw_put_image_shm(struct dri_drawable *drawable,189int shmid, char *shmaddr, unsigned offset,190unsigned offset_x,191int x, int y, unsigned width, unsigned height,192unsigned stride)193{194__DRIdrawable *dPriv = drawable->dPriv;195196put_image_shm(dPriv, shmid, shmaddr, offset, offset_x, x, y, width, height, stride);197}198199static inline void200drisw_present_texture(struct pipe_context *pipe, __DRIdrawable *dPriv,201struct pipe_resource *ptex, struct pipe_box *sub_box)202{203struct dri_drawable *drawable = dri_drawable(dPriv);204struct dri_screen *screen = dri_screen(drawable->sPriv);205206if (screen->swrast_no_present)207return;208209screen->base.screen->flush_frontbuffer(screen->base.screen, pipe, ptex, 0, 0, drawable, sub_box);210}211212static inline void213drisw_invalidate_drawable(__DRIdrawable *dPriv)214{215struct dri_drawable *drawable = dri_drawable(dPriv);216217drawable->texture_stamp = dPriv->lastStamp - 1;218219p_atomic_inc(&drawable->base.stamp);220}221222static inline void223drisw_copy_to_front(struct pipe_context *pipe,224__DRIdrawable * dPriv,225struct pipe_resource *ptex)226{227drisw_present_texture(pipe, dPriv, ptex, NULL);228229drisw_invalidate_drawable(dPriv);230}231232/*233* Backend functions for st_framebuffer interface and swap_buffers.234*/235236static void237drisw_swap_buffers(__DRIdrawable *dPriv)238{239struct dri_context *ctx = dri_get_current(dPriv->driScreenPriv);240struct dri_drawable *drawable = dri_drawable(dPriv);241struct pipe_resource *ptex;242243if (!ctx)244return;245246ptex = drawable->textures[ST_ATTACHMENT_BACK_LEFT];247248if (ptex) {249if (ctx->pp)250pp_run(ctx->pp, ptex, ptex, drawable->textures[ST_ATTACHMENT_DEPTH_STENCIL]);251252if (ctx->hud)253hud_run(ctx->hud, ctx->st->cso_context, ptex);254255ctx->st->flush(ctx->st, ST_FLUSH_FRONT, NULL, NULL, NULL);256257if (drawable->stvis.samples > 1) {258/* Resolve the back buffer. */259dri_pipe_blit(ctx->st->pipe,260drawable->textures[ST_ATTACHMENT_BACK_LEFT],261drawable->msaa_textures[ST_ATTACHMENT_BACK_LEFT]);262}263264drisw_copy_to_front(ctx->st->pipe, dPriv, ptex);265}266}267268static void269drisw_copy_sub_buffer(__DRIdrawable *dPriv, int x, int y,270int w, int h)271{272struct dri_context *ctx = dri_get_current(dPriv->driScreenPriv);273struct dri_drawable *drawable = dri_drawable(dPriv);274struct pipe_resource *ptex;275struct pipe_box box;276if (!ctx)277return;278279ptex = drawable->textures[ST_ATTACHMENT_BACK_LEFT];280281if (ptex) {282if (ctx->pp && drawable->textures[ST_ATTACHMENT_DEPTH_STENCIL])283pp_run(ctx->pp, ptex, ptex, drawable->textures[ST_ATTACHMENT_DEPTH_STENCIL]);284285ctx->st->flush(ctx->st, ST_FLUSH_FRONT, NULL, NULL, NULL);286287u_box_2d(x, dPriv->h - y - h, w, h, &box);288drisw_present_texture(ctx->st->pipe, dPriv, ptex, &box);289}290}291292static bool293drisw_flush_frontbuffer(struct dri_context *ctx,294struct dri_drawable *drawable,295enum st_attachment_type statt)296{297struct pipe_resource *ptex;298299if (!ctx || statt != ST_ATTACHMENT_FRONT_LEFT)300return false;301302if (drawable->stvis.samples > 1) {303/* Resolve the front buffer. */304dri_pipe_blit(ctx->st->pipe,305drawable->textures[ST_ATTACHMENT_FRONT_LEFT],306drawable->msaa_textures[ST_ATTACHMENT_FRONT_LEFT]);307}308ptex = drawable->textures[statt];309310if (ptex) {311drisw_copy_to_front(ctx->st->pipe, ctx->dPriv, ptex);312}313314return true;315}316317/**318* Allocate framebuffer attachments.319*320* During fixed-size operation, the function keeps allocating new attachments321* as they are requested. Unused attachments are not removed, not until the322* framebuffer is resized or destroyed.323*/324static void325drisw_allocate_textures(struct dri_context *stctx,326struct dri_drawable *drawable,327const enum st_attachment_type *statts,328unsigned count)329{330struct dri_screen *screen = dri_screen(drawable->sPriv);331const __DRIswrastLoaderExtension *loader = drawable->dPriv->driScreenPriv->swrast_loader;332struct pipe_resource templ;333unsigned width, height;334boolean resized;335unsigned i;336337width = drawable->dPriv->w;338height = drawable->dPriv->h;339340resized = (drawable->old_w != width ||341drawable->old_h != height);342343/* remove outdated textures */344if (resized) {345for (i = 0; i < ST_ATTACHMENT_COUNT; i++) {346pipe_resource_reference(&drawable->textures[i], NULL);347pipe_resource_reference(&drawable->msaa_textures[i], NULL);348}349}350351memset(&templ, 0, sizeof(templ));352templ.target = screen->target;353templ.width0 = width;354templ.height0 = height;355templ.depth0 = 1;356templ.array_size = 1;357templ.last_level = 0;358359for (i = 0; i < count; i++) {360enum pipe_format format;361unsigned bind;362363/* the texture already exists or not requested */364if (drawable->textures[statts[i]])365continue;366367dri_drawable_get_format(drawable, statts[i], &format, &bind);368369/* if we don't do any present, no need for display targets */370if (statts[i] != ST_ATTACHMENT_DEPTH_STENCIL && !screen->swrast_no_present)371bind |= PIPE_BIND_DISPLAY_TARGET;372373if (format == PIPE_FORMAT_NONE)374continue;375376templ.format = format;377templ.bind = bind;378templ.nr_samples = 0;379templ.nr_storage_samples = 0;380381if (statts[i] == ST_ATTACHMENT_FRONT_LEFT &&382screen->base.screen->resource_create_front &&383loader->base.version >= 3) {384drawable->textures[statts[i]] =385screen->base.screen->resource_create_front(screen->base.screen, &templ, (const void *)drawable);386} else387drawable->textures[statts[i]] =388screen->base.screen->resource_create(screen->base.screen, &templ);389390if (drawable->stvis.samples > 1) {391templ.bind = templ.bind &392~(PIPE_BIND_SCANOUT | PIPE_BIND_SHARED | PIPE_BIND_DISPLAY_TARGET);393templ.nr_samples = drawable->stvis.samples;394templ.nr_storage_samples = drawable->stvis.samples;395drawable->msaa_textures[statts[i]] =396screen->base.screen->resource_create(screen->base.screen, &templ);397398dri_pipe_blit(stctx->st->pipe,399drawable->msaa_textures[statts[i]],400drawable->textures[statts[i]]);401}402}403404drawable->old_w = width;405drawable->old_h = height;406}407408static void409drisw_update_tex_buffer(struct dri_drawable *drawable,410struct dri_context *ctx,411struct pipe_resource *res)412{413__DRIdrawable *dPriv = drawable->dPriv;414415struct st_context *st_ctx = (struct st_context *)ctx->st;416struct pipe_context *pipe = st_ctx->pipe;417struct pipe_transfer *transfer;418char *map;419int x, y, w, h;420int ximage_stride, line;421int cpp = util_format_get_blocksize(res->format);422423get_drawable_info(dPriv, &x, &y, &w, &h);424425map = pipe_texture_map(pipe, res,4260, 0, // level, layer,427PIPE_MAP_WRITE,428x, y, w, h, &transfer);429430/* Copy the Drawable content to the mapped texture buffer */431if (!get_image_shm(dPriv, x, y, w, h, res))432get_image(dPriv, x, y, w, h, map);433434/* The pipe transfer has a pitch rounded up to the nearest 64 pixels.435get_image() has a pitch rounded up to 4 bytes. */436ximage_stride = ((w * cpp) + 3) & -4;437for (line = h-1; line; --line) {438memmove(&map[line * transfer->stride],439&map[line * ximage_stride],440ximage_stride);441}442443pipe_texture_unmap(pipe, transfer);444}445446static __DRIimageExtension driSWImageExtension = {447.base = { __DRI_IMAGE, 6 },448449.createImageFromRenderbuffer = dri2_create_image_from_renderbuffer,450.createImageFromTexture = dri2_create_from_texture,451.destroyImage = dri2_destroy_image,452};453454static const __DRIrobustnessExtension dri2Robustness = {455.base = { __DRI2_ROBUSTNESS, 1 }456};457458/*459* Backend function for init_screen.460*/461462static const __DRIextension *drisw_screen_extensions[] = {463&driTexBufferExtension.base,464&dri2RendererQueryExtension.base,465&dri2ConfigQueryExtension.base,466&dri2FenceExtension.base,467&dri2NoErrorExtension.base,468&driSWImageExtension.base,469&dri2FlushControlExtension.base,470NULL471};472473static const __DRIextension *drisw_robust_screen_extensions[] = {474&driTexBufferExtension.base,475&dri2RendererQueryExtension.base,476&dri2ConfigQueryExtension.base,477&dri2FenceExtension.base,478&dri2NoErrorExtension.base,479&dri2Robustness.base,480&driSWImageExtension.base,481&dri2FlushControlExtension.base,482NULL483};484485static const struct drisw_loader_funcs drisw_lf = {486.get_image = drisw_get_image,487.put_image = drisw_put_image,488.put_image2 = drisw_put_image2489};490491static const struct drisw_loader_funcs drisw_shm_lf = {492.get_image = drisw_get_image,493.put_image = drisw_put_image,494.put_image2 = drisw_put_image2,495.put_image_shm = drisw_put_image_shm496};497498static const __DRIconfig **499drisw_init_screen(__DRIscreen * sPriv)500{501const __DRIswrastLoaderExtension *loader = sPriv->swrast_loader;502const __DRIconfig **configs;503struct dri_screen *screen;504struct pipe_screen *pscreen = NULL;505const struct drisw_loader_funcs *lf = &drisw_lf;506507screen = CALLOC_STRUCT(dri_screen);508if (!screen)509return NULL;510511screen->sPriv = sPriv;512screen->fd = -1;513514screen->swrast_no_present = debug_get_option_swrast_no_present();515516sPriv->driverPrivate = (void *)screen;517518if (loader->base.version >= 4) {519if (loader->putImageShm)520lf = &drisw_shm_lf;521}522523if (pipe_loader_sw_probe_dri(&screen->dev, lf)) {524dri_init_options(screen);525526pscreen = pipe_loader_create_screen(screen->dev);527}528529if (!pscreen)530goto fail;531532configs = dri_init_screen_helper(screen, pscreen);533if (!configs)534goto fail;535536if (pscreen->get_param(pscreen, PIPE_CAP_DEVICE_RESET_STATUS_QUERY)) {537sPriv->extensions = drisw_robust_screen_extensions;538screen->has_reset_status_query = true;539}540else541sPriv->extensions = drisw_screen_extensions;542screen->lookup_egl_image = dri2_lookup_egl_image;543544return configs;545fail:546dri_destroy_screen_helper(screen);547if (screen->dev)548pipe_loader_release(&screen->dev, 1);549FREE(screen);550return NULL;551}552553static boolean554drisw_create_buffer(__DRIscreen * sPriv,555__DRIdrawable * dPriv,556const struct gl_config * visual, boolean isPixmap)557{558struct dri_drawable *drawable = NULL;559560if (!dri_create_buffer(sPriv, dPriv, visual, isPixmap))561return FALSE;562563drawable = dPriv->driverPrivate;564565drawable->allocate_textures = drisw_allocate_textures;566drawable->update_drawable_info = drisw_update_drawable_info;567drawable->flush_frontbuffer = drisw_flush_frontbuffer;568drawable->update_tex_buffer = drisw_update_tex_buffer;569570return TRUE;571}572573/**574* DRI driver virtual function table.575*576* DRI versions differ in their implementation of init_screen and swap_buffers.577*/578const struct __DriverAPIRec galliumsw_driver_api = {579.InitScreen = drisw_init_screen,580.DestroyScreen = dri_destroy_screen,581.CreateContext = dri_create_context,582.DestroyContext = dri_destroy_context,583.CreateBuffer = drisw_create_buffer,584.DestroyBuffer = dri_destroy_buffer,585.SwapBuffers = drisw_swap_buffers,586.MakeCurrent = dri_make_current,587.UnbindContext = dri_unbind_context,588.CopySubBuffer = drisw_copy_sub_buffer,589};590591/* This is the table of extensions that the loader will dlsym() for. */592const __DRIextension *galliumsw_driver_extensions[] = {593&driCoreExtension.base,594&driSWRastExtension.base,595&driCopySubBufferExtension.base,596&gallium_config_options.base,597NULL598};599600/* vim: set sw=3 ts=8 sts=3 expandtab: */601602603