/**********************************************************
* Copyright 2010 VMware, Inc. All rights reserved.
*
* Permission is hereby granted, free of charge, to any person
* obtaining a copy of this software and associated documentation
* files (the "Software"), to deal in the Software without
* restriction, including without limitation the rights to use, copy,
* modify, merge, publish, distribute, sublicense, and/or sell copies
* of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
* BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
* ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*
**********************************************************/
#include "wrapper_sw_winsys.h"
#include "pipe/p_format.h"
#include "pipe/p_state.h"
#include "state_tracker/sw_winsys.h"
#include "util/u_memory.h"
#include "util/u_inlines.h"
/*
* This code wraps a pipe_screen and exposes a sw_winsys interface for use
* with software resterizers. This code is used by the DRM based winsys to
* allow access to the drm driver.
*
* We must borrow the whole stack because only the pipe screen knows how
* to decode the content of a buffer. Or how to create a buffer that
* can still be used by drivers using real hardware (as the case is
* with software st/xorg but hw st/dri).
*
* We also need a pipe context for the transfers.
*/
struct wrapper_sw_winsys
{
struct sw_winsys base;
struct pipe_screen *screen;
struct pipe_context *pipe;
enum pipe_texture_target target;
};
struct wrapper_sw_displaytarget
{
struct wrapper_sw_winsys *winsys;
struct pipe_resource *tex;
struct pipe_transfer *transfer;
unsigned map_count;
unsigned stride; /**< because we get stride at create */
void *ptr;
};
static INLINE struct wrapper_sw_winsys *
wrapper_sw_winsys(struct sw_winsys *ws)
{
return (struct wrapper_sw_winsys *)ws;
}
static INLINE struct wrapper_sw_displaytarget *
wrapper_sw_displaytarget(struct sw_displaytarget *dt)
{
return (struct wrapper_sw_displaytarget *)dt;
}
/*
* Functions
*/
static boolean
wsw_dt_get_stride(struct wrapper_sw_displaytarget *wdt, unsigned *stride)
{
struct pipe_context *pipe = wdt->winsys->pipe;
struct pipe_resource *tex = wdt->tex;
struct pipe_transfer *tr;
tr = pipe_get_transfer(pipe, tex, 0, 0,
PIPE_TRANSFER_READ_WRITE,
0, 0, wdt->tex->width0, wdt->tex->height0);
if (!tr)
return FALSE;
*stride = tr->stride;
wdt->stride = tr->stride;
pipe->transfer_destroy(pipe, tr);
return TRUE;
}
static struct sw_displaytarget *
wsw_dt_wrap_texture(struct wrapper_sw_winsys *wsw,
struct pipe_resource *tex, unsigned *stride)
{
struct wrapper_sw_displaytarget *wdt = CALLOC_STRUCT(wrapper_sw_displaytarget);
if (!wdt)
goto err_unref;
wdt->tex = tex;
wdt->winsys = wsw;
if (!wsw_dt_get_stride(wdt, stride))
goto err_free;
return (struct sw_displaytarget *)wdt;
err_free:
FREE(wdt);
err_unref:
pipe_resource_reference(&tex, NULL);
return NULL;
}
static struct sw_displaytarget *
wsw_dt_create(struct sw_winsys *ws,
unsigned bind,
enum pipe_format format,
unsigned width, unsigned height,
unsigned alignment,
unsigned *stride)
{
struct wrapper_sw_winsys *wsw = wrapper_sw_winsys(ws);
struct pipe_resource templ;
struct pipe_resource *tex;
/*
* XXX Why don't we just get the template.
*/
memset(&templ, 0, sizeof(templ));
templ.target = wsw->target;
templ.width0 = width;
templ.height0 = height;
templ.depth0 = 1;
templ.array_size = 1;
templ.format = format;
templ.bind = bind;
/* XXX alignment: we can't do anything about this */
tex = wsw->screen->resource_create(wsw->screen, &templ);
if (!tex)
return NULL;
return wsw_dt_wrap_texture(wsw, tex, stride);
}
static struct sw_displaytarget *
wsw_dt_from_handle(struct sw_winsys *ws,
const struct pipe_resource *templ,
struct winsys_handle *whandle,
unsigned *stride)
{
struct wrapper_sw_winsys *wsw = wrapper_sw_winsys(ws);
struct pipe_resource *tex;
tex = wsw->screen->resource_from_handle(wsw->screen, templ, whandle);
if (!tex)
return NULL;
return wsw_dt_wrap_texture(wsw, tex, stride);
}
static boolean
wsw_dt_get_handle(struct sw_winsys *ws,
struct sw_displaytarget *dt,
struct winsys_handle *whandle)
{
struct wrapper_sw_winsys *wsw = wrapper_sw_winsys(ws);
struct wrapper_sw_displaytarget *wdt = wrapper_sw_displaytarget(dt);
struct pipe_resource *tex = wdt->tex;
return wsw->screen->resource_get_handle(wsw->screen, tex, whandle);
}
static void *
wsw_dt_map(struct sw_winsys *ws,
struct sw_displaytarget *dt,
unsigned flags)
{
struct wrapper_sw_displaytarget *wdt = wrapper_sw_displaytarget(dt);
struct pipe_context *pipe = wdt->winsys->pipe;
struct pipe_resource *tex = wdt->tex;
struct pipe_transfer *tr;
void *ptr;
if (!wdt->map_count) {
assert(!wdt->transfer);
tr = pipe_get_transfer(pipe, tex, 0, 0,
PIPE_TRANSFER_READ_WRITE,
0, 0, wdt->tex->width0, wdt->tex->height0);
if (!tr)
return NULL;
ptr = pipe->transfer_map(pipe, tr);
if (!ptr)
goto err;
wdt->transfer = tr;
wdt->ptr = ptr;
/* XXX Handle this case */
assert(tr->stride == wdt->stride);
}
wdt->map_count++;
return wdt->ptr;
err:
pipe->transfer_destroy(pipe, tr);
return NULL;
}
static void
wsw_dt_unmap(struct sw_winsys *ws,
struct sw_displaytarget *dt)
{
struct wrapper_sw_displaytarget *wdt = wrapper_sw_displaytarget(dt);
struct pipe_context *pipe = wdt->winsys->pipe;
assert(wdt->transfer);
wdt->map_count--;
if (wdt->map_count)
return;
pipe->transfer_unmap(pipe, wdt->transfer);
pipe->transfer_destroy(pipe, wdt->transfer);
pipe->flush(pipe, NULL);
wdt->transfer = NULL;
}
static void
wsw_dt_destroy(struct sw_winsys *ws,
struct sw_displaytarget *dt)
{
struct wrapper_sw_displaytarget *wdt = wrapper_sw_displaytarget(dt);
pipe_resource_reference(&wdt->tex, NULL);
FREE(wdt);
}
static void
wsw_destroy(struct sw_winsys *ws)
{
struct wrapper_sw_winsys *wsw = wrapper_sw_winsys(ws);
wsw->pipe->destroy(wsw->pipe);
wsw->screen->destroy(wsw->screen);
FREE(wsw);
}
struct sw_winsys *
wrapper_sw_winsys_wrap_pipe_screen(struct pipe_screen *screen)
{
struct wrapper_sw_winsys *wsw = CALLOC_STRUCT(wrapper_sw_winsys);
if (!wsw)
goto err;
wsw->base.displaytarget_create = wsw_dt_create;
wsw->base.displaytarget_from_handle = wsw_dt_from_handle;
wsw->base.displaytarget_get_handle = wsw_dt_get_handle;
wsw->base.displaytarget_map = wsw_dt_map;
wsw->base.displaytarget_unmap = wsw_dt_unmap;
wsw->base.displaytarget_destroy = wsw_dt_destroy;
wsw->base.destroy = wsw_destroy;
wsw->screen = screen;
wsw->pipe = screen->context_create(screen, NULL);
if (!wsw->pipe)
goto err_free;
if(screen->get_param(screen, PIPE_CAP_NPOT_TEXTURES))
wsw->target = PIPE_TEXTURE_2D;
else
wsw->target = PIPE_TEXTURE_RECT;
return &wsw->base;
err_free:
FREE(wsw);
err:
return NULL;
}
struct pipe_screen *
wrapper_sw_winsys_dewrap_pipe_screen(struct sw_winsys *ws)
{
struct wrapper_sw_winsys *wsw = wrapper_sw_winsys(ws);
struct pipe_screen *screen = wsw->screen;
wsw->pipe->destroy(wsw->pipe);
/* don't destroy the screen its needed later on */
FREE(wsw);
return screen;
}