blob: 50ed669ba303a65e690b3b1d07c7a108a33e9fa8 [file] [log] [blame]
/*
* Mesa 3-D graphics library
* Version: 7.9
*
* Copyright (C) 2010 LunarG Inc.
*
* 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.
*
* Authors:
* Chia-I Wu <olv@lunarg.com>
*/
#include "util/u_memory.h"
#include "util/u_string.h"
#include "util/u_inlines.h"
#include "util/u_pointer.h"
#include "util/u_dl.h"
#include "egldriver.h"
#include "eglimage.h"
#include "eglmutex.h"
#include "egl_g3d.h"
#include "egl_g3d_st.h"
struct egl_g3d_st_manager {
struct st_manager base;
_EGLDisplay *display;
};
static INLINE struct egl_g3d_st_manager *
egl_g3d_st_manager(struct st_manager *smapi)
{
return (struct egl_g3d_st_manager *) smapi;
}
static boolean
egl_g3d_st_manager_get_egl_image(struct st_manager *smapi,
void *egl_image,
struct st_egl_image *out)
{
struct egl_g3d_st_manager *gsmapi = egl_g3d_st_manager(smapi);
EGLImageKHR handle = (EGLImageKHR) egl_image;
_EGLImage *img;
struct egl_g3d_image *gimg;
/* this is called from state trackers */
_eglLockMutex(&gsmapi->display->Mutex);
img = _eglLookupImage(handle, gsmapi->display);
if (!img) {
_eglUnlockMutex(&gsmapi->display->Mutex);
return FALSE;
}
gimg = egl_g3d_image(img);
out->texture = NULL;
pipe_resource_reference(&out->texture, gimg->texture);
out->level = gimg->level;
out->layer = gimg->layer;
_eglUnlockMutex(&gsmapi->display->Mutex);
return TRUE;
}
static int
egl_g3d_st_manager_get_param(struct st_manager *smapi,
enum st_manager_param param)
{
return 0;
}
struct st_manager *
egl_g3d_create_st_manager(_EGLDisplay *dpy)
{
struct egl_g3d_display *gdpy = egl_g3d_display(dpy);
struct egl_g3d_st_manager *gsmapi;
gsmapi = CALLOC_STRUCT(egl_g3d_st_manager);
if (gsmapi) {
gsmapi->display = dpy;
gsmapi->base.screen = gdpy->native->screen;
gsmapi->base.get_egl_image = egl_g3d_st_manager_get_egl_image;
gsmapi->base.get_param = egl_g3d_st_manager_get_param;
}
return &gsmapi->base;;
}
void
egl_g3d_destroy_st_manager(struct st_manager *smapi)
{
struct egl_g3d_st_manager *gsmapi = egl_g3d_st_manager(smapi);
FREE(gsmapi);
}
static boolean
egl_g3d_st_framebuffer_flush_front_pbuffer(struct st_framebuffer_iface *stfbi,
enum st_attachment_type statt)
{
return TRUE;
}
static void
pbuffer_reference_openvg_image(struct egl_g3d_surface *gsurf)
{
/* TODO */
}
static void
pbuffer_allocate_pbuffer_texture(struct egl_g3d_surface *gsurf)
{
struct egl_g3d_display *gdpy =
egl_g3d_display(gsurf->base.Resource.Display);
struct pipe_screen *screen = gdpy->native->screen;
struct pipe_resource templ, *ptex;
memset(&templ, 0, sizeof(templ));
templ.target = PIPE_TEXTURE_2D;
templ.last_level = 0;
templ.width0 = gsurf->base.Width;
templ.height0 = gsurf->base.Height;
templ.depth0 = 1;
templ.array_size = 1;
templ.format = gsurf->stvis.color_format;
/* for rendering and binding to texture */
templ.bind = PIPE_BIND_RENDER_TARGET | PIPE_BIND_SAMPLER_VIEW;
ptex = screen->resource_create(screen, &templ);
gsurf->render_texture = ptex;
}
static boolean
egl_g3d_st_framebuffer_validate_pbuffer(struct st_framebuffer_iface *stfbi,
const enum st_attachment_type *statts,
unsigned count,
struct pipe_resource **out)
{
_EGLSurface *surf = (_EGLSurface *) stfbi->st_manager_private;
struct egl_g3d_surface *gsurf = egl_g3d_surface(surf);
unsigned i;
for (i = 0; i < count; i++) {
out[i] = NULL;
if (gsurf->stvis.render_buffer != statts[i])
continue;
if (!gsurf->render_texture) {
switch (gsurf->client_buffer_type) {
case EGL_NONE:
pbuffer_allocate_pbuffer_texture(gsurf);
break;
case EGL_OPENVG_IMAGE:
pbuffer_reference_openvg_image(gsurf);
break;
default:
break;
}
if (!gsurf->render_texture)
return FALSE;
}
pipe_resource_reference(&out[i], gsurf->render_texture);
}
return TRUE;
}
static boolean
egl_g3d_st_framebuffer_flush_front(struct st_framebuffer_iface *stfbi,
enum st_attachment_type statt)
{
_EGLSurface *surf = (_EGLSurface *) stfbi->st_manager_private;
struct egl_g3d_surface *gsurf = egl_g3d_surface(surf);
struct native_present_control ctrl;
memset(&ctrl, 0, sizeof(ctrl));
ctrl.natt = NATIVE_ATTACHMENT_FRONT_LEFT;
return gsurf->native->present(gsurf->native, &ctrl);
}
static boolean
egl_g3d_st_framebuffer_validate(struct st_framebuffer_iface *stfbi,
const enum st_attachment_type *statts,
unsigned count,
struct pipe_resource **out)
{
_EGLSurface *surf = (_EGLSurface *) stfbi->st_manager_private;
struct egl_g3d_surface *gsurf = egl_g3d_surface(surf);
struct pipe_resource *textures[NUM_NATIVE_ATTACHMENTS];
uint attachment_mask = 0;
unsigned i;
for (i = 0; i < count; i++) {
int natt;
switch (statts[i]) {
case ST_ATTACHMENT_FRONT_LEFT:
natt = NATIVE_ATTACHMENT_FRONT_LEFT;
break;
case ST_ATTACHMENT_BACK_LEFT:
natt = NATIVE_ATTACHMENT_BACK_LEFT;
break;
case ST_ATTACHMENT_FRONT_RIGHT:
natt = NATIVE_ATTACHMENT_FRONT_RIGHT;
break;
case ST_ATTACHMENT_BACK_RIGHT:
natt = NATIVE_ATTACHMENT_BACK_RIGHT;
break;
default:
natt = -1;
break;
}
if (natt >= 0)
attachment_mask |= 1 << natt;
}
if (!gsurf->native->validate(gsurf->native, attachment_mask,
&gsurf->sequence_number, textures, &gsurf->base.Width,
&gsurf->base.Height))
return FALSE;
for (i = 0; i < count; i++) {
struct pipe_resource *tex;
int natt;
switch (statts[i]) {
case ST_ATTACHMENT_FRONT_LEFT:
natt = NATIVE_ATTACHMENT_FRONT_LEFT;
break;
case ST_ATTACHMENT_BACK_LEFT:
natt = NATIVE_ATTACHMENT_BACK_LEFT;
break;
case ST_ATTACHMENT_FRONT_RIGHT:
natt = NATIVE_ATTACHMENT_FRONT_RIGHT;
break;
case ST_ATTACHMENT_BACK_RIGHT:
natt = NATIVE_ATTACHMENT_BACK_RIGHT;
break;
default:
natt = -1;
break;
}
if (natt >= 0) {
tex = textures[natt];
if (statts[i] == stfbi->visual->render_buffer)
pipe_resource_reference(&gsurf->render_texture, tex);
if (attachment_mask & (1 << natt)) {
/* transfer the ownership to the caller */
out[i] = tex;
attachment_mask &= ~(1 << natt);
}
else {
/* the attachment is listed more than once */
pipe_resource_reference(&out[i], tex);
}
}
}
return TRUE;
}
struct st_framebuffer_iface *
egl_g3d_create_st_framebuffer(_EGLSurface *surf)
{
struct egl_g3d_surface *gsurf = egl_g3d_surface(surf);
struct st_framebuffer_iface *stfbi;
stfbi = CALLOC_STRUCT(st_framebuffer_iface);
if (!stfbi)
return NULL;
stfbi->visual = &gsurf->stvis;
p_atomic_set(&stfbi->stamp, 1);
if (gsurf->base.Type != EGL_PBUFFER_BIT) {
stfbi->flush_front = egl_g3d_st_framebuffer_flush_front;
stfbi->validate = egl_g3d_st_framebuffer_validate;
}
else {
stfbi->flush_front = egl_g3d_st_framebuffer_flush_front_pbuffer;
stfbi->validate = egl_g3d_st_framebuffer_validate_pbuffer;
}
stfbi->st_manager_private = (void *) &gsurf->base;
return stfbi;
}
void
egl_g3d_destroy_st_framebuffer(struct st_framebuffer_iface *stfbi)
{
FREE(stfbi);
}