mesa: cleanup

git-svn-id: svn://kolibrios.org@4360 a494cfbc-eb01-0410-851d-a64ba20cac60
This commit is contained in:
Sergey Semyonov (Serge) 2013-12-15 13:16:18 +00:00
parent ab3eee4bd8
commit 4fdea57f1b
25 changed files with 0 additions and 21080 deletions

File diff suppressed because it is too large Load Diff

View File

@ -1,543 +0,0 @@
/*
* Copyright © 2011 Intel Corporation
*
* 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 (including the next
* paragraph) 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:
* Kristian Høgsberg <krh@bitplanet.net>
*/
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <xf86drm.h>
//#include <dlfcn.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <kos32sys.h>
#include <pixlib2.h>
#define EGL_EGLEXT_PROTOTYPES
#include <EGL/egl.h>
#include <EGL/eglext.h>
#include "egl_dri2.h"
int sna_bitmap_from_handle(bitmap_t *bitmap, uint32_t handle);
void sna_set_bo_handle(bitmap_t *bitmap, int handle);
int sna_blit_tex(bitmap_t *bitmap, int scale, int dst_x, int dst_y,
int w, int h, int src_x, int src_y);
static struct gbm_bo *
lock_front_buffer(struct gbm_surface *_surf)
{
struct gbm_dri_surface *surf = (struct gbm_dri_surface *) _surf;
struct dri2_egl_surface *dri2_surf = surf->dri_private;
struct gbm_bo *bo;
if (dri2_surf->current == NULL) {
_eglError(EGL_BAD_SURFACE, "no front buffer");
return NULL;
}
bo = dri2_surf->current->bo;
dri2_surf->current->locked = 1;
dri2_surf->current = NULL;
return bo;
}
static void
release_buffer(struct gbm_surface *_surf, struct gbm_bo *bo)
{
struct gbm_dri_surface *surf = (struct gbm_dri_surface *) _surf;
struct dri2_egl_surface *dri2_surf = surf->dri_private;
int i;
for (i = 0; i < ARRAY_SIZE(dri2_surf->color_buffers); i++) {
if (dri2_surf->color_buffers[i].bo == bo) {
dri2_surf->color_buffers[i].locked = 0;
}
}
}
static int
has_free_buffers(struct gbm_surface *_surf)
{
struct gbm_dri_surface *surf = (struct gbm_dri_surface *) _surf;
struct dri2_egl_surface *dri2_surf = surf->dri_private;
int i;
for (i = 0; i < ARRAY_SIZE(dri2_surf->color_buffers); i++)
if (!dri2_surf->color_buffers[i].locked)
return 1;
return 0;
}
static _EGLSurface *
dri2_create_surface(_EGLDriver *drv, _EGLDisplay *disp, EGLint type,
_EGLConfig *conf, EGLNativeWindowType window,
const EGLint *attrib_list)
{
struct dri2_egl_display *dri2_dpy = dri2_egl_display(disp);
struct dri2_egl_config *dri2_conf = dri2_egl_config(conf);
struct dri2_egl_surface *dri2_surf;
struct gbm_dri_surface *surf;
(void) drv;
dri2_surf = calloc(1, sizeof *dri2_surf);
if (!dri2_surf) {
_eglError(EGL_BAD_ALLOC, "dri2_create_surface");
return NULL;
}
if (!_eglInitSurface(&dri2_surf->base, disp, type, conf, attrib_list))
goto cleanup_surf;
switch (type) {
case EGL_WINDOW_BIT:
if (!window)
return NULL;
surf = gbm_dri_surface((struct gbm_surface *) window);
dri2_surf->gbm_surf = surf;
dri2_surf->base.Width = surf->base.width;
dri2_surf->base.Height = surf->base.height;
surf->dri_private = dri2_surf;
break;
default:
goto cleanup_surf;
}
dri2_surf->dri_drawable =
(*dri2_dpy->dri2->createNewDrawable) (dri2_dpy->dri_screen,
dri2_conf->dri_double_config,
dri2_surf->gbm_surf);
if (dri2_surf->dri_drawable == NULL) {
_eglError(EGL_BAD_ALLOC, "dri2->createNewDrawable");
goto cleanup_surf;
}
return &dri2_surf->base;
cleanup_surf:
free(dri2_surf);
return NULL;
}
static _EGLSurface *
dri2_create_window_surface(_EGLDriver *drv, _EGLDisplay *disp,
_EGLConfig *conf, EGLNativeWindowType window,
const EGLint *attrib_list)
{
return dri2_create_surface(drv, disp, EGL_WINDOW_BIT, conf,
window, attrib_list);
}
static EGLBoolean
dri2_destroy_surface(_EGLDriver *drv, _EGLDisplay *disp, _EGLSurface *surf)
{
struct dri2_egl_display *dri2_dpy = dri2_egl_display(disp);
struct dri2_egl_surface *dri2_surf = dri2_egl_surface(surf);
int i;
if (!_eglPutSurface(surf))
return EGL_TRUE;
(*dri2_dpy->core->destroyDrawable)(dri2_surf->dri_drawable);
for (i = 0; i < ARRAY_SIZE(dri2_surf->color_buffers); i++) {
if (dri2_surf->color_buffers[i].bo)
gbm_bo_destroy(dri2_surf->color_buffers[i].bo);
}
for (i = 0; i < __DRI_BUFFER_COUNT; i++) {
if (dri2_surf->dri_buffers[i])
dri2_dpy->dri2->releaseBuffer(dri2_dpy->dri_screen,
dri2_surf->dri_buffers[i]);
}
free(surf);
return EGL_TRUE;
}
static int
get_back_bo(struct dri2_egl_surface *dri2_surf, __DRIbuffer *buffer)
{
struct dri2_egl_display *dri2_dpy =
dri2_egl_display(dri2_surf->base.Resource.Display);
struct gbm_dri_bo *bo;
struct gbm_dri_surface *surf = dri2_surf->gbm_surf;
int i, name, pitch;
if (dri2_surf->back == NULL) {
for (i = 0; i < ARRAY_SIZE(dri2_surf->color_buffers); i++) {
if (!dri2_surf->color_buffers[i].locked) {
dri2_surf->back = &dri2_surf->color_buffers[i];
break;
}
}
}
if (dri2_surf->back == NULL)
return -1;
if (dri2_surf->back->bo == NULL)
dri2_surf->back->bo = gbm_bo_create(&dri2_dpy->gbm_dri->base.base,
surf->base.width, surf->base.height,
surf->base.format, surf->base.flags);
if (dri2_surf->back->bo == NULL)
return -1;
bo = (struct gbm_dri_bo *) dri2_surf->back->bo;
dri2_dpy->image->queryImage(bo->image, __DRI_IMAGE_ATTRIB_NAME, &name);
dri2_dpy->image->queryImage(bo->image, __DRI_IMAGE_ATTRIB_STRIDE, &pitch);
buffer->attachment = __DRI_BUFFER_BACK_LEFT;
buffer->name = name;
buffer->pitch = pitch;
buffer->cpp = 4;
buffer->flags = 0;
return 0;
}
static int
get_aux_bo(struct dri2_egl_surface *dri2_surf,
unsigned int attachment, unsigned int format, __DRIbuffer *buffer)
{
struct dri2_egl_display *dri2_dpy =
dri2_egl_display(dri2_surf->base.Resource.Display);
__DRIbuffer *b = dri2_surf->dri_buffers[attachment];
if (b == NULL) {
b = dri2_dpy->dri2->allocateBuffer(dri2_dpy->dri_screen,
attachment, format,
dri2_surf->base.Width,
dri2_surf->base.Height);
dri2_surf->dri_buffers[attachment] = b;
}
if (b == NULL)
return -1;
memcpy(buffer, b, sizeof *buffer);
return 0;
}
static __DRIbuffer *
dri2_get_buffers_with_format(__DRIdrawable *driDrawable,
int *width, int *height,
unsigned int *attachments, int count,
int *out_count, void *loaderPrivate)
{
struct dri2_egl_surface *dri2_surf = loaderPrivate;
int i, j;
dri2_surf->buffer_count = 0;
for (i = 0, j = 0; i < 2 * count; i += 2, j++) {
assert(attachments[i] < __DRI_BUFFER_COUNT);
assert(dri2_surf->buffer_count < 5);
switch (attachments[i]) {
case __DRI_BUFFER_BACK_LEFT:
if (get_back_bo(dri2_surf, &dri2_surf->buffers[j]) < 0) {
_eglError(EGL_BAD_ALLOC, "failed to allocate color buffer");
return NULL;
}
break;
default:
if (get_aux_bo(dri2_surf, attachments[i], attachments[i + 1],
&dri2_surf->buffers[j]) < 0) {
_eglError(EGL_BAD_ALLOC, "failed to allocate aux buffer");
return NULL;
}
break;
}
}
*out_count = j;
if (j == 0)
return NULL;
*width = dri2_surf->base.Width;
*height = dri2_surf->base.Height;
return dri2_surf->buffers;
}
static __DRIbuffer *
dri2_get_buffers(__DRIdrawable * driDrawable,
int *width, int *height,
unsigned int *attachments, int count,
int *out_count, void *loaderPrivate)
{
unsigned int *attachments_with_format;
__DRIbuffer *buffer;
const unsigned int format = 32;
int i;
attachments_with_format = calloc(count * 2, sizeof(unsigned int));
if (!attachments_with_format) {
*out_count = 0;
return NULL;
}
for (i = 0; i < count; ++i) {
attachments_with_format[2*i] = attachments[i];
attachments_with_format[2*i + 1] = format;
}
buffer =
dri2_get_buffers_with_format(driDrawable,
width, height,
attachments_with_format, count,
out_count, loaderPrivate);
free(attachments_with_format);
return buffer;
}
static void
dri2_flush_front_buffer(__DRIdrawable * driDrawable, void *loaderPrivate)
{
(void) driDrawable;
(void) loaderPrivate;
}
static EGLBoolean
dri2_swap_buffers(_EGLDriver *drv, _EGLDisplay *disp, _EGLSurface *draw)
{
struct dri2_egl_display *dri2_dpy = dri2_egl_display(disp);
struct dri2_egl_surface *dri2_surf = dri2_egl_surface(draw);
__DRIbuffer buffer;
static bitmap_t bm;
int i;
if (dri2_surf->base.Type == EGL_WINDOW_BIT) {
if (dri2_surf->current)
_eglError(EGL_BAD_SURFACE, "dri2_swap_buffers");
for (i = 0; i < ARRAY_SIZE(dri2_surf->color_buffers); i++)
if (dri2_surf->color_buffers[i].age > 0)
dri2_surf->color_buffers[i].age++;
if ( (dri2_surf->back != NULL) &&
(dri2_surf->back->bo != NULL))
{
struct gbm_dri_bo *bo;
bo = (struct gbm_dri_bo *)dri2_surf->back->bo;
if(bm.width == 0)
{
printf("%s bo: %p handle: %d width: %d height: %d pitch %d format %x\n",
__FUNCTION__, bo, bo->base.base.handle.s32, bo->base.base.width,
bo->base.base.height, (int)bo->base.base.stride,
bo->base.base.format);
bm.width = bo->base.base.width;
bm.height = bo->base.base.height;
bm.pitch = (int)bo->base.base.stride;
bm.max_width = bo->base.base.width;
bm.max_height = bo->base.base.height;
bm.flags = HW_TEX_BLIT;
if( sna_bitmap_from_handle(&bm, bo->base.base.handle.s32))
{
printf("sna_bitmap_from_handle failed\n");
}
}
if( bm.handle != 0)
{
sna_set_bo_handle(&bm, bo->base.base.handle.s32);
sna_blit_tex(&bm, 0, 5, 22, bm.width, bm.height, 0, 0);
}
}
dri2_surf->current = dri2_surf->back;
dri2_surf->current->age = 1;
dri2_surf->back = NULL;
}
(*dri2_dpy->flush->flush)(dri2_surf->dri_drawable);
(*dri2_dpy->flush->invalidate)(dri2_surf->dri_drawable);
return EGL_TRUE;
}
static EGLint
dri2_query_buffer_age(_EGLDriver *drv,
_EGLDisplay *disp, _EGLSurface *surface)
{
struct dri2_egl_surface *dri2_surf = dri2_egl_surface(surface);
__DRIbuffer buffer;
if (get_back_bo(dri2_surf, &buffer) < 0) {
_eglError(EGL_BAD_ALLOC, "dri2_query_buffer_age");
return 0;
}
return dri2_surf->back->age;
}
static _EGLImage *
dri2_create_image_khr_pixmap(_EGLDisplay *disp, _EGLContext *ctx,
EGLClientBuffer buffer, const EGLint *attr_list)
{
struct dri2_egl_display *dri2_dpy = dri2_egl_display(disp);
struct gbm_dri_bo *dri_bo = gbm_dri_bo((struct gbm_bo *) buffer);
struct dri2_egl_image *dri2_img;
dri2_img = malloc(sizeof *dri2_img);
if (!dri2_img) {
_eglError(EGL_BAD_ALLOC, "dri2_create_image_khr_pixmap");
return NULL;
}
if (!_eglInitImage(&dri2_img->base, disp)) {
free(dri2_img);
return NULL;
}
dri2_img->dri_image = dri2_dpy->image->dupImage(dri_bo->image, dri2_img);
if (dri2_img->dri_image == NULL) {
free(dri2_img);
_eglError(EGL_BAD_ALLOC, "dri2_create_image_khr_pixmap");
return NULL;
}
return &dri2_img->base;
}
static _EGLImage *
dri2_drm_create_image_khr(_EGLDriver *drv, _EGLDisplay *disp,
_EGLContext *ctx, EGLenum target,
EGLClientBuffer buffer, const EGLint *attr_list)
{
(void) drv;
switch (target) {
case EGL_NATIVE_PIXMAP_KHR:
return dri2_create_image_khr_pixmap(disp, ctx, buffer, attr_list);
default:
return dri2_create_image_khr(drv, disp, ctx, target, buffer, attr_list);
}
}
#if 0
static int
dri2_drm_authenticate(_EGLDisplay *disp, uint32_t id)
{
struct dri2_egl_display *dri2_dpy = dri2_egl_display(disp);
return drmAuthMagic(dri2_dpy->fd, id);
}
#endif
EGLBoolean
dri2_initialize_drm(_EGLDriver *drv, _EGLDisplay *disp)
{
struct dri2_egl_display *dri2_dpy;
struct gbm_device *gbm;
int fd = -1;
int i;
dri2_dpy = calloc(1, sizeof *dri2_dpy);
if (!dri2_dpy)
return _eglError(EGL_BAD_ALLOC, "eglInitialize");
disp->DriverData = (void *) dri2_dpy;
gbm = disp->PlatformDisplay;
if (gbm == NULL) {
fd = get_service("DISPLAY");
dri2_dpy->own_device = 1;
gbm = gbm_create_device(fd);
if (gbm == NULL)
return EGL_FALSE;
}
if (strcmp(gbm_device_get_backend_name(gbm), "drm") != 0) {
free(dri2_dpy);
return EGL_FALSE;
}
dri2_dpy->gbm_dri = gbm_dri_device(gbm);
if (dri2_dpy->gbm_dri->base.type != GBM_DRM_DRIVER_TYPE_DRI) {
free(dri2_dpy);
return EGL_FALSE;
}
dri2_dpy->fd = fd;
dri2_dpy->device_name = strdup("drm device"); //dri2_get_device_name_for_fd(dri2_dpy->fd);
dri2_dpy->driver_name = dri2_dpy->gbm_dri->base.driver_name;
dri2_dpy->dri_screen = dri2_dpy->gbm_dri->screen;
dri2_dpy->core = dri2_dpy->gbm_dri->core;
dri2_dpy->dri2 = dri2_dpy->gbm_dri->dri2;
dri2_dpy->image = dri2_dpy->gbm_dri->image;
dri2_dpy->flush = dri2_dpy->gbm_dri->flush;
dri2_dpy->driver_configs = dri2_dpy->gbm_dri->driver_configs;
dri2_dpy->gbm_dri->lookup_image = dri2_lookup_egl_image;
dri2_dpy->gbm_dri->lookup_user_data = disp;
dri2_dpy->gbm_dri->get_buffers = dri2_get_buffers;
dri2_dpy->gbm_dri->flush_front_buffer = dri2_flush_front_buffer;
dri2_dpy->gbm_dri->get_buffers_with_format = dri2_get_buffers_with_format;
dri2_dpy->gbm_dri->base.base.surface_lock_front_buffer = lock_front_buffer;
dri2_dpy->gbm_dri->base.base.surface_release_buffer = release_buffer;
dri2_dpy->gbm_dri->base.base.surface_has_free_buffers = has_free_buffers;
dri2_setup_screen(disp);
for (i = 0; dri2_dpy->driver_configs[i]; i++)
dri2_add_config(disp, dri2_dpy->driver_configs[i],
i + 1, 0, EGL_WINDOW_BIT, NULL, NULL);
drv->API.CreateWindowSurface = dri2_create_window_surface;
drv->API.CreatePbufferSurface = dri2_create_pbuffer_surface;
drv->API.DestroySurface = dri2_destroy_surface;
drv->API.SwapBuffers = dri2_swap_buffers;
drv->API.CreateImageKHR = dri2_drm_create_image_khr;
drv->API.QueryBufferAge = dri2_query_buffer_age;
disp->Extensions.EXT_buffer_age = EGL_TRUE;
#ifdef HAVE_WAYLAND_PLATFORM
disp->Extensions.WL_bind_wayland_display = EGL_TRUE;
#endif
// dri2_dpy->authenticate = dri2_drm_authenticate;
/* we're supporting EGL 1.4 */
disp->VersionMajor = 1;
disp->VersionMinor = 4;
return EGL_TRUE;
}

File diff suppressed because it is too large Load Diff

View File

@ -1,213 +0,0 @@
/**************************************************************************
*
* Copyright 2010 LunarG, 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, sub license, 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 (including the
* next paragraph) 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 <stdlib.h>
#include <string.h>
#define EGL_EGLEXT_PROTOTYPES
#include <EGL/egl.h>
#include <EGL/eglext.h>
#include "egllog.h"
#include "eglarray.h"
/**
* Grow the size of the array.
*/
static EGLBoolean
_eglGrowArray(_EGLArray *array)
{
EGLint new_size;
void **elems;
new_size = array->MaxSize;
while (new_size <= array->Size)
new_size *= 2;
elems = realloc(array->Elements, new_size * sizeof(array->Elements[0]));
if (!elems) {
_eglLog(_EGL_DEBUG, "failed to grow %s array to %d",
array->Name, new_size);
return EGL_FALSE;
}
array->Elements = elems;
array->MaxSize = new_size;
return EGL_TRUE;
}
/**
* Create an array.
*/
_EGLArray *
_eglCreateArray(const char *name, EGLint init_size)
{
_EGLArray *array;
array = calloc(1, sizeof(*array));
if (array) {
array->Name = name;
array->MaxSize = (init_size > 0) ? init_size : 1;
if (!_eglGrowArray(array)) {
free(array);
array = NULL;
}
}
return array;
}
/**
* Destroy an array, optionally free the data.
*/
void
_eglDestroyArray(_EGLArray *array, void (*free_cb)(void *))
{
if (free_cb) {
EGLint i;
for (i = 0; i < array->Size; i++)
free_cb(array->Elements[i]);
}
free(array->Elements);
free(array);
}
/**
* Append a element to an array.
*/
void
_eglAppendArray(_EGLArray *array, void *elem)
{
if (array->Size >= array->MaxSize && !_eglGrowArray(array))
return;
array->Elements[array->Size++] = elem;
}
/**
* Erase an element from an array.
*/
void
_eglEraseArray(_EGLArray *array, EGLint i, void (*free_cb)(void *))
{
if (free_cb)
free_cb(array->Elements[i]);
if (i < array->Size - 1) {
memmove(&array->Elements[i], &array->Elements[i + 1],
(array->Size - i - 1) * sizeof(array->Elements[0]));
}
array->Size--;
}
/**
* Find in an array for the given element.
*/
void *
_eglFindArray(_EGLArray *array, void *elem)
{
EGLint i;
if (!array)
return NULL;
for (i = 0; i < array->Size; i++)
if (array->Elements[i] == elem)
return elem;
return NULL;
}
/**
* Filter an array and return the number of filtered elements.
*/
EGLint
_eglFilterArray(_EGLArray *array, void **data, EGLint size,
_EGLArrayForEach filter, void *filter_data)
{
EGLint count = 0, i;
if (!array)
return 0;
if (filter) {
for (i = 0; i < array->Size; i++) {
if (filter(array->Elements[i], filter_data)) {
if (data && count < size)
data[count] = array->Elements[i];
count++;
}
if (data && count >= size)
break;
}
}
else {
if (data) {
count = (size < array->Size) ? size : array->Size;
memcpy(data, array->Elements, count * sizeof(array->Elements[0]));
}
else {
count = array->Size;
}
}
return count;
}
/**
* Flatten an array by converting array elements into another form and store
* them in a buffer.
*/
EGLint
_eglFlattenArray(_EGLArray *array, void *buffer, EGLint elem_size, EGLint size,
_EGLArrayForEach flatten)
{
EGLint i, count;
if (!array)
return 0;
count = array->Size;
if (buffer) {
/* do not exceed buffer size */
if (count > size)
count = size;
for (i = 0; i < count; i++)
flatten(array->Elements[i],
(void *) ((char *) buffer + elem_size * i));
}
return count;
}

View File

@ -1,852 +0,0 @@
/**************************************************************************
*
* Copyright 2008 Tungsten Graphics, Inc., Cedar Park, Texas.
* Copyright 2009-2010 Chia-I Wu <olvaffe@gmail.com>
* Copyright 2010-2011 LunarG, 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, sub license, 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 (including the
* next paragraph) 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.
*
**************************************************************************/
/**
* EGL Configuration (pixel format) functions.
*/
#include <stdlib.h>
#include <string.h>
#include <assert.h>
#include "eglconfig.h"
#include "egldisplay.h"
#include "eglcurrent.h"
#include "egllog.h"
#define MIN2(A, B) (((A) < (B)) ? (A) : (B))
/**
* Init the given _EGLconfig to default values.
* \param id the configuration's ID.
*
* Note that id must be positive for the config to be valid.
* It is also recommended that when there are N configs, their
* IDs are from 1 to N respectively.
*/
void
_eglInitConfig(_EGLConfig *conf, _EGLDisplay *dpy, EGLint id)
{
memset(conf, 0, sizeof(*conf));
conf->Display = dpy;
/* some attributes take non-zero default values */
conf->ConfigID = id;
conf->ConfigCaveat = EGL_NONE;
conf->TransparentType = EGL_NONE;
conf->NativeVisualType = EGL_NONE;
conf->ColorBufferType = EGL_RGB_BUFFER;
}
/**
* Link a config to its display and return the handle of the link.
* The handle can be passed to client directly.
*
* Note that we just save the ptr to the config (we don't copy the config).
*/
PUBLIC EGLConfig
_eglLinkConfig(_EGLConfig *conf)
{
_EGLDisplay *dpy = conf->Display;
/* sanity check */
assert(dpy && conf->ConfigID > 0);
if (!dpy->Configs) {
dpy->Configs = _eglCreateArray("Config", 16);
if (!dpy->Configs)
return (EGLConfig) NULL;
}
_eglAppendArray(dpy->Configs, (void *) conf);
return (EGLConfig) conf;
}
/**
* Lookup a handle to find the linked config.
* Return NULL if the handle has no corresponding linked config.
*/
_EGLConfig *
_eglLookupConfig(EGLConfig config, _EGLDisplay *dpy)
{
_EGLConfig *conf;
if (!dpy)
return NULL;
conf = (_EGLConfig *) _eglFindArray(dpy->Configs, (void *) config);
if (conf)
assert(conf->Display == dpy);
return conf;
}
enum {
/* types */
ATTRIB_TYPE_INTEGER,
ATTRIB_TYPE_BOOLEAN,
ATTRIB_TYPE_BITMASK,
ATTRIB_TYPE_ENUM,
ATTRIB_TYPE_PSEUDO, /* non-queryable */
ATTRIB_TYPE_PLATFORM, /* platform-dependent */
/* criteria */
ATTRIB_CRITERION_EXACT,
ATTRIB_CRITERION_ATLEAST,
ATTRIB_CRITERION_MASK,
ATTRIB_CRITERION_SPECIAL,
ATTRIB_CRITERION_IGNORE
};
/* EGL spec Table 3.1 and 3.4 */
static const struct {
EGLint attr;
EGLint type;
EGLint criterion;
EGLint default_value;
} _eglValidationTable[] =
{
/* core */
{ EGL_BUFFER_SIZE, ATTRIB_TYPE_INTEGER,
ATTRIB_CRITERION_ATLEAST,
0 },
{ EGL_RED_SIZE, ATTRIB_TYPE_INTEGER,
ATTRIB_CRITERION_ATLEAST,
0 },
{ EGL_GREEN_SIZE, ATTRIB_TYPE_INTEGER,
ATTRIB_CRITERION_ATLEAST,
0 },
{ EGL_BLUE_SIZE, ATTRIB_TYPE_INTEGER,
ATTRIB_CRITERION_ATLEAST,
0 },
{ EGL_LUMINANCE_SIZE, ATTRIB_TYPE_INTEGER,
ATTRIB_CRITERION_ATLEAST,
0 },
{ EGL_ALPHA_SIZE, ATTRIB_TYPE_INTEGER,
ATTRIB_CRITERION_ATLEAST,
0 },
{ EGL_ALPHA_MASK_SIZE, ATTRIB_TYPE_INTEGER,
ATTRIB_CRITERION_ATLEAST,
0 },
{ EGL_BIND_TO_TEXTURE_RGB, ATTRIB_TYPE_BOOLEAN,
ATTRIB_CRITERION_EXACT,
EGL_DONT_CARE },
{ EGL_BIND_TO_TEXTURE_RGBA, ATTRIB_TYPE_BOOLEAN,
ATTRIB_CRITERION_EXACT,
EGL_DONT_CARE },
{ EGL_COLOR_BUFFER_TYPE, ATTRIB_TYPE_ENUM,
ATTRIB_CRITERION_EXACT,
EGL_RGB_BUFFER },
{ EGL_CONFIG_CAVEAT, ATTRIB_TYPE_ENUM,
ATTRIB_CRITERION_EXACT,
EGL_DONT_CARE },
{ EGL_CONFIG_ID, ATTRIB_TYPE_INTEGER,
ATTRIB_CRITERION_EXACT,
EGL_DONT_CARE },
{ EGL_CONFORMANT, ATTRIB_TYPE_BITMASK,
ATTRIB_CRITERION_MASK,
0 },
{ EGL_DEPTH_SIZE, ATTRIB_TYPE_INTEGER,
ATTRIB_CRITERION_ATLEAST,
0 },
{ EGL_LEVEL, ATTRIB_TYPE_PLATFORM,
ATTRIB_CRITERION_EXACT,
0 },
{ EGL_MAX_PBUFFER_WIDTH, ATTRIB_TYPE_INTEGER,
ATTRIB_CRITERION_IGNORE,
0 },
{ EGL_MAX_PBUFFER_HEIGHT, ATTRIB_TYPE_INTEGER,
ATTRIB_CRITERION_IGNORE,
0 },
{ EGL_MAX_PBUFFER_PIXELS, ATTRIB_TYPE_INTEGER,
ATTRIB_CRITERION_IGNORE,
0 },
{ EGL_MAX_SWAP_INTERVAL, ATTRIB_TYPE_INTEGER,
ATTRIB_CRITERION_EXACT,
EGL_DONT_CARE },
{ EGL_MIN_SWAP_INTERVAL, ATTRIB_TYPE_INTEGER,
ATTRIB_CRITERION_EXACT,
EGL_DONT_CARE },
{ EGL_NATIVE_RENDERABLE, ATTRIB_TYPE_BOOLEAN,
ATTRIB_CRITERION_EXACT,
EGL_DONT_CARE },
{ EGL_NATIVE_VISUAL_ID, ATTRIB_TYPE_PLATFORM,
ATTRIB_CRITERION_IGNORE,
0 },
{ EGL_NATIVE_VISUAL_TYPE, ATTRIB_TYPE_PLATFORM,
ATTRIB_CRITERION_EXACT,
EGL_DONT_CARE },
{ EGL_RENDERABLE_TYPE, ATTRIB_TYPE_BITMASK,
ATTRIB_CRITERION_MASK,
EGL_OPENGL_ES_BIT },
{ EGL_SAMPLE_BUFFERS, ATTRIB_TYPE_INTEGER,
ATTRIB_CRITERION_ATLEAST,
0 },
{ EGL_SAMPLES, ATTRIB_TYPE_INTEGER,
ATTRIB_CRITERION_ATLEAST,
0 },
{ EGL_STENCIL_SIZE, ATTRIB_TYPE_INTEGER,
ATTRIB_CRITERION_ATLEAST,
0 },
{ EGL_SURFACE_TYPE, ATTRIB_TYPE_BITMASK,
ATTRIB_CRITERION_MASK,
EGL_WINDOW_BIT },
{ EGL_TRANSPARENT_TYPE, ATTRIB_TYPE_ENUM,
ATTRIB_CRITERION_EXACT,
EGL_NONE },
{ EGL_TRANSPARENT_RED_VALUE, ATTRIB_TYPE_INTEGER,
ATTRIB_CRITERION_EXACT,
EGL_DONT_CARE },
{ EGL_TRANSPARENT_GREEN_VALUE, ATTRIB_TYPE_INTEGER,
ATTRIB_CRITERION_EXACT,
EGL_DONT_CARE },
{ EGL_TRANSPARENT_BLUE_VALUE, ATTRIB_TYPE_INTEGER,
ATTRIB_CRITERION_EXACT,
EGL_DONT_CARE },
{ EGL_MATCH_NATIVE_PIXMAP, ATTRIB_TYPE_PSEUDO,
ATTRIB_CRITERION_SPECIAL,
EGL_NONE },
/* extensions */
{ EGL_Y_INVERTED_NOK, ATTRIB_TYPE_BOOLEAN,
ATTRIB_CRITERION_EXACT,
EGL_DONT_CARE }
};
/**
* Return true if a config is valid. When for_matching is true,
* EGL_DONT_CARE is accepted as a valid attribute value, and checks
* for conflicting attribute values are skipped.
*
* Note that some attributes are platform-dependent and are not
* checked.
*/
EGLBoolean
_eglValidateConfig(const _EGLConfig *conf, EGLBoolean for_matching)
{
EGLint i, attr, val;
EGLBoolean valid = EGL_TRUE;
/* check attributes by their types */
for (i = 0; i < ARRAY_SIZE(_eglValidationTable); i++) {
EGLint mask;
attr = _eglValidationTable[i].attr;
val = _eglGetConfigKey(conf, attr);
switch (_eglValidationTable[i].type) {
case ATTRIB_TYPE_INTEGER:
switch (attr) {
case EGL_CONFIG_ID:
/* config id must be positive */
if (val <= 0)
valid = EGL_FALSE;
break;
case EGL_SAMPLE_BUFFERS:
/* there can be at most 1 sample buffer */
if (val > 1 || val < 0)
valid = EGL_FALSE;
break;
default:
if (val < 0)
valid = EGL_FALSE;
break;
}
break;
case ATTRIB_TYPE_BOOLEAN:
if (val != EGL_TRUE && val != EGL_FALSE)
valid = EGL_FALSE;
break;
case ATTRIB_TYPE_ENUM:
switch (attr) {
case EGL_CONFIG_CAVEAT:
if (val != EGL_NONE && val != EGL_SLOW_CONFIG &&
val != EGL_NON_CONFORMANT_CONFIG)
valid = EGL_FALSE;
break;
case EGL_TRANSPARENT_TYPE:
if (val != EGL_NONE && val != EGL_TRANSPARENT_RGB)
valid = EGL_FALSE;
break;
case EGL_COLOR_BUFFER_TYPE:
if (val != EGL_RGB_BUFFER && val != EGL_LUMINANCE_BUFFER)
valid = EGL_FALSE;
break;
default:
assert(0);
break;
}
break;
case ATTRIB_TYPE_BITMASK:
switch (attr) {
case EGL_SURFACE_TYPE:
mask = EGL_PBUFFER_BIT |
EGL_PIXMAP_BIT |
EGL_WINDOW_BIT |
EGL_VG_COLORSPACE_LINEAR_BIT |
EGL_VG_ALPHA_FORMAT_PRE_BIT |
EGL_MULTISAMPLE_RESOLVE_BOX_BIT |
EGL_SWAP_BEHAVIOR_PRESERVED_BIT;
#ifdef EGL_MESA_screen_surface
if (conf->Display->Extensions.MESA_screen_surface)
mask |= EGL_SCREEN_BIT_MESA;
#endif
break;
case EGL_RENDERABLE_TYPE:
case EGL_CONFORMANT:
mask = EGL_OPENGL_ES_BIT |
EGL_OPENVG_BIT |
EGL_OPENGL_ES2_BIT |
EGL_OPENGL_ES3_BIT_KHR |
EGL_OPENGL_BIT;
break;
default:
assert(0);
mask = 0;
break;
}
if (val & ~mask)
valid = EGL_FALSE;
break;
case ATTRIB_TYPE_PLATFORM:
/* unable to check platform-dependent attributes here */
break;
case ATTRIB_TYPE_PSEUDO:
/* pseudo attributes should not be set */
if (val != 0)
valid = EGL_FALSE;
break;
default:
assert(0);
break;
}
if (!valid && for_matching) {
/* accept EGL_DONT_CARE as a valid value */
if (val == EGL_DONT_CARE)
valid = EGL_TRUE;
if (_eglValidationTable[i].criterion == ATTRIB_CRITERION_SPECIAL)
valid = EGL_TRUE;
}
if (!valid) {
_eglLog(_EGL_DEBUG,
"attribute 0x%04x has an invalid value 0x%x", attr, val);
break;
}
}
/* any invalid attribute value should have been catched */
if (!valid || for_matching)
return valid;
/* now check for conflicting attribute values */
switch (conf->ColorBufferType) {
case EGL_RGB_BUFFER:
if (conf->LuminanceSize)
valid = EGL_FALSE;
if (conf->RedSize + conf->GreenSize +
conf->BlueSize + conf->AlphaSize != conf->BufferSize)
valid = EGL_FALSE;
break;
case EGL_LUMINANCE_BUFFER:
if (conf->RedSize || conf->GreenSize || conf->BlueSize)
valid = EGL_FALSE;
if (conf->LuminanceSize + conf->AlphaSize != conf->BufferSize)
valid = EGL_FALSE;
break;
}
if (!valid) {
_eglLog(_EGL_DEBUG, "conflicting color buffer type and channel sizes");
return EGL_FALSE;
}
if (!conf->SampleBuffers && conf->Samples)
valid = EGL_FALSE;
if (!valid) {
_eglLog(_EGL_DEBUG, "conflicting samples and sample buffers");
return EGL_FALSE;
}
if (!(conf->SurfaceType & EGL_WINDOW_BIT)) {
if (conf->NativeVisualID != 0 || conf->NativeVisualType != EGL_NONE)
valid = EGL_FALSE;
}
if (!(conf->SurfaceType & EGL_PBUFFER_BIT)) {
if (conf->BindToTextureRGB || conf->BindToTextureRGBA)
valid = EGL_FALSE;
}
if (!valid) {
_eglLog(_EGL_DEBUG, "conflicting surface type and native visual/texture binding");
return EGL_FALSE;
}
return valid;
}
/**
* Return true if a config matches the criteria. This and
* _eglParseConfigAttribList together implement the algorithm
* described in "Selection of EGLConfigs".
*
* Note that attributes that are special (currently, only
* EGL_MATCH_NATIVE_PIXMAP) are ignored.
*/
EGLBoolean
_eglMatchConfig(const _EGLConfig *conf, const _EGLConfig *criteria)
{
EGLint attr, val, i;
EGLBoolean matched = EGL_TRUE;
printf("_eglMatchConfig\n");
asm volatile ("int3");
for (i = 0; i < ARRAY_SIZE(_eglValidationTable); i++) {
EGLint cmp;
if (_eglValidationTable[i].criterion == ATTRIB_CRITERION_IGNORE)
continue;
attr = _eglValidationTable[i].attr;
cmp = _eglGetConfigKey(criteria, attr);
if (cmp == EGL_DONT_CARE)
continue;
val = _eglGetConfigKey(conf, attr);
switch (_eglValidationTable[i].criterion) {
case ATTRIB_CRITERION_EXACT:
if (val != cmp)
matched = EGL_FALSE;
break;
case ATTRIB_CRITERION_ATLEAST:
if (val < cmp)
matched = EGL_FALSE;
break;
case ATTRIB_CRITERION_MASK:
if ((val & cmp) != cmp)
matched = EGL_FALSE;
break;
case ATTRIB_CRITERION_SPECIAL:
/* ignored here */
break;
default:
assert(0);
break;
}
if (!matched) {
#ifndef DEBUG
/* only print the common errors when DEBUG is not defined */
if (attr != EGL_RENDERABLE_TYPE)
break;
#endif
// _eglLog(_EGL_DEBUG,
// "the value (0x%x) of attribute 0x%04x did not meet the criteria (0x%x)",
// val, attr, cmp);
printf("the value (0x%x) of attribute 0x%04x did not meet the criteria (0x%x)",
val, attr, cmp);
break;
}
}
return matched;
}
static INLINE EGLBoolean
_eglIsConfigAttribValid(_EGLConfig *conf, EGLint attr)
{
if (_eglOffsetOfConfig(attr) < 0)
return EGL_FALSE;
switch (attr) {
case EGL_Y_INVERTED_NOK:
return conf->Display->Extensions.NOK_texture_from_pixmap;
default:
break;
}
return EGL_TRUE;
}
/**
* Initialize a criteria config from the given attribute list.
* Return EGL_FALSE if any of the attribute is invalid.
*/
EGLBoolean
_eglParseConfigAttribList(_EGLConfig *conf, _EGLDisplay *dpy,
const EGLint *attrib_list)
{
EGLint attr, val, i;
_eglInitConfig(conf, dpy, EGL_DONT_CARE);
/* reset to default values */
for (i = 0; i < ARRAY_SIZE(_eglValidationTable); i++) {
attr = _eglValidationTable[i].attr;
val = _eglValidationTable[i].default_value;
_eglSetConfigKey(conf, attr, val);
}
/* parse the list */
for (i = 0; attrib_list && attrib_list[i] != EGL_NONE; i += 2) {
attr = attrib_list[i];
val = attrib_list[i + 1];
if (!_eglIsConfigAttribValid(conf, attr))
return EGL_FALSE;
_eglSetConfigKey(conf, attr, val);
}
if (!_eglValidateConfig(conf, EGL_TRUE))
return EGL_FALSE;
/* EGL_LEVEL and EGL_MATCH_NATIVE_PIXMAP cannot be EGL_DONT_CARE */
if (conf->Level == EGL_DONT_CARE ||
conf->MatchNativePixmap == EGL_DONT_CARE)
return EGL_FALSE;
/* ignore other attributes when EGL_CONFIG_ID is given */
if (conf->ConfigID != EGL_DONT_CARE) {
for (i = 0; i < ARRAY_SIZE(_eglValidationTable); i++) {
attr = _eglValidationTable[i].attr;
if (attr != EGL_CONFIG_ID)
_eglSetConfigKey(conf, attr, EGL_DONT_CARE);
}
}
else {
if (!(conf->SurfaceType & EGL_WINDOW_BIT))
conf->NativeVisualType = EGL_DONT_CARE;
if (conf->TransparentType == EGL_NONE) {
conf->TransparentRedValue = EGL_DONT_CARE;
conf->TransparentGreenValue = EGL_DONT_CARE;
conf->TransparentBlueValue = EGL_DONT_CARE;
}
}
return EGL_TRUE;
}
/**
* Decide the ordering of conf1 and conf2, under the given criteria.
* When compare_id is true, this implements the algorithm described
* in "Sorting of EGLConfigs". When compare_id is false,
* EGL_CONFIG_ID is not compared.
*
* It returns a negative integer if conf1 is considered to come
* before conf2; a positive integer if conf2 is considered to come
* before conf1; zero if the ordering cannot be decided.
*
* Note that EGL_NATIVE_VISUAL_TYPE is platform-dependent and is
* ignored here.
*/
EGLint
_eglCompareConfigs(const _EGLConfig *conf1, const _EGLConfig *conf2,
const _EGLConfig *criteria, EGLBoolean compare_id)
{
const EGLint compare_attribs[] = {
EGL_BUFFER_SIZE,
EGL_SAMPLE_BUFFERS,
EGL_SAMPLES,
EGL_DEPTH_SIZE,
EGL_STENCIL_SIZE,
EGL_ALPHA_MASK_SIZE,
};
EGLint val1, val2;
EGLint i;
if (conf1 == conf2)
return 0;
/* the enum values have the desired ordering */
assert(EGL_NONE < EGL_SLOW_CONFIG);
assert(EGL_SLOW_CONFIG < EGL_NON_CONFORMANT_CONFIG);
val1 = conf1->ConfigCaveat - conf2->ConfigCaveat;
if (val1)
return val1;
/* the enum values have the desired ordering */
assert(EGL_RGB_BUFFER < EGL_LUMINANCE_BUFFER);
val1 = conf1->ColorBufferType - conf2->ColorBufferType;
if (val1)
return val1;
if (criteria) {
val1 = val2 = 0;
if (conf1->ColorBufferType == EGL_RGB_BUFFER) {
if (criteria->RedSize > 0) {
val1 += conf1->RedSize;
val2 += conf2->RedSize;
}
if (criteria->GreenSize > 0) {
val1 += conf1->GreenSize;
val2 += conf2->GreenSize;
}
if (criteria->BlueSize > 0) {
val1 += conf1->BlueSize;
val2 += conf2->BlueSize;
}
}
else {
if (criteria->LuminanceSize > 0) {
val1 += conf1->LuminanceSize;
val2 += conf2->LuminanceSize;
}
}
if (criteria->AlphaSize > 0) {
val1 += conf1->AlphaSize;
val2 += conf2->AlphaSize;
}
}
else {
/* assume the default criteria, which gives no specific ordering */
val1 = val2 = 0;
}
/* for color bits, larger one is preferred */
if (val1 != val2)
return (val2 - val1);
for (i = 0; i < ARRAY_SIZE(compare_attribs); i++) {
val1 = _eglGetConfigKey(conf1, compare_attribs[i]);
val2 = _eglGetConfigKey(conf2, compare_attribs[i]);
if (val1 != val2)
return (val1 - val2);
}
/* EGL_NATIVE_VISUAL_TYPE cannot be compared here */
return (compare_id) ? (conf1->ConfigID - conf2->ConfigID) : 0;
}
static INLINE
void _eglSwapConfigs(const _EGLConfig **conf1, const _EGLConfig **conf2)
{
const _EGLConfig *tmp = *conf1;
*conf1 = *conf2;
*conf2 = tmp;
}
/**
* Quick sort an array of configs. This differs from the standard
* qsort() in that the compare function accepts an additional
* argument.
*/
static void
_eglSortConfigs(const _EGLConfig **configs, EGLint count,
EGLint (*compare)(const _EGLConfig *, const _EGLConfig *,
void *),
void *priv_data)
{
const EGLint pivot = 0;
EGLint i, j;
if (count <= 1)
return;
_eglSwapConfigs(&configs[pivot], &configs[count / 2]);
i = 1;
j = count - 1;
do {
while (i < count && compare(configs[i], configs[pivot], priv_data) < 0)
i++;
while (compare(configs[j], configs[pivot], priv_data) > 0)
j--;
if (i < j) {
_eglSwapConfigs(&configs[i], &configs[j]);
i++;
j--;
}
else if (i == j) {
i++;
j--;
break;
}
} while (i <= j);
_eglSwapConfigs(&configs[pivot], &configs[j]);
_eglSortConfigs(configs, j, compare, priv_data);
_eglSortConfigs(configs + i, count - i, compare, priv_data);
}
/**
* A helper function for implementing eglChooseConfig. See _eglFilterArray and
* _eglSortConfigs for the meanings of match and compare.
*/
EGLBoolean
_eglFilterConfigArray(_EGLArray *array, EGLConfig *configs,
EGLint config_size, EGLint *num_configs,
EGLBoolean (*match)(const _EGLConfig *, void *),
EGLint (*compare)(const _EGLConfig *, const _EGLConfig *,
void *),
void *priv_data)
{
_EGLConfig **configList;
EGLint i, count;
if (!num_configs)
return _eglError(EGL_BAD_PARAMETER, "eglChooseConfigs");
/* get the number of matched configs */
count = _eglFilterArray(array, NULL, 0,
(_EGLArrayForEach) match, priv_data);
if (!count) {
*num_configs = count;
printf("_eglFilterConfigArray count %d\n", count);
return EGL_TRUE;
}
configList = malloc(sizeof(*configList) * count);
if (!configList)
return _eglError(EGL_BAD_ALLOC, "eglChooseConfig(out of memory)");
/* get the matched configs */
_eglFilterArray(array, (void **) configList, count,
(_EGLArrayForEach) match, priv_data);
/* perform sorting of configs */
if (configs && count) {
_eglSortConfigs((const _EGLConfig **) configList, count,
compare, priv_data);
count = MIN2(count, config_size);
for (i = 0; i < count; i++)
configs[i] = _eglGetConfigHandle(configList[i]);
}
free(configList);
*num_configs = count;
return EGL_TRUE;
}
static EGLBoolean
_eglFallbackMatch(const _EGLConfig *conf, void *priv_data)
{
return _eglMatchConfig(conf, (const _EGLConfig *) priv_data);
}
static EGLint
_eglFallbackCompare(const _EGLConfig *conf1, const _EGLConfig *conf2,
void *priv_data)
{
return _eglCompareConfigs(conf1, conf2,
(const _EGLConfig *) priv_data, EGL_TRUE);
}
/**
* Typical fallback routine for eglChooseConfig
*/
EGLBoolean
_eglChooseConfig(_EGLDriver *drv, _EGLDisplay *disp, const EGLint *attrib_list,
EGLConfig *configs, EGLint config_size, EGLint *num_configs)
{
_EGLConfig criteria;
if (!_eglParseConfigAttribList(&criteria, disp, attrib_list))
return _eglError(EGL_BAD_ATTRIBUTE, "eglChooseConfig");
printf("%s attrib %p size %d\n", __FUNCTION__, attrib_list, config_size);
asm volatile ("int3");
return _eglFilterConfigArray(disp->Configs,
configs, config_size, num_configs,
_eglFallbackMatch, _eglFallbackCompare,
(void *) &criteria);
}
/**
* Fallback for eglGetConfigAttrib.
*/
EGLBoolean
_eglGetConfigAttrib(_EGLDriver *drv, _EGLDisplay *dpy, _EGLConfig *conf,
EGLint attribute, EGLint *value)
{
if (!_eglIsConfigAttribValid(conf, attribute))
return _eglError(EGL_BAD_ATTRIBUTE, "eglGetConfigAttrib");
/* nonqueryable attributes */
switch (attribute) {
case EGL_MATCH_NATIVE_PIXMAP:
return _eglError(EGL_BAD_ATTRIBUTE, "eglGetConfigAttrib");
break;
default:
break;
}
if (!value)
return _eglError(EGL_BAD_PARAMETER, "eglGetConfigAttrib");
*value = _eglGetConfigKey(conf, attribute);
return EGL_TRUE;
}
static EGLBoolean
_eglFlattenConfig(void *elem, void *buffer)
{
_EGLConfig *conf = (_EGLConfig *) elem;
EGLConfig *handle = (EGLConfig *) buffer;
*handle = _eglGetConfigHandle(conf);
return EGL_TRUE;
}
/**
* Fallback for eglGetConfigs.
*/
EGLBoolean
_eglGetConfigs(_EGLDriver *drv, _EGLDisplay *disp, EGLConfig *configs,
EGLint config_size, EGLint *num_config)
{
if (!num_config)
return _eglError(EGL_BAD_PARAMETER, "eglGetConfigs");
*num_config = _eglFlattenArray(disp->Configs, (void *) configs,
sizeof(configs[0]), config_size, _eglFlattenConfig);
return EGL_TRUE;
}

View File

@ -1,618 +0,0 @@
/**************************************************************************
*
* Copyright 2008 Tungsten Graphics, Inc., Cedar Park, Texas.
* Copyright 2009-2010 Chia-I Wu <olvaffe@gmail.com>
* Copyright 2010-2011 LunarG, 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, sub license, 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 (including the
* next paragraph) 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 <assert.h>
#include <stdlib.h>
#include <string.h>
#include "eglconfig.h"
#include "eglcontext.h"
#include "egldisplay.h"
#include "eglcurrent.h"
#include "eglsurface.h"
#include "egllog.h"
/**
* Return the API bit (one of EGL_xxx_BIT) of the context.
*/
static EGLint
_eglGetContextAPIBit(_EGLContext *ctx)
{
EGLint bit = 0;
switch (ctx->ClientAPI) {
case EGL_OPENGL_ES_API:
switch (ctx->ClientMajorVersion) {
case 1:
bit = EGL_OPENGL_ES_BIT;
break;
case 2:
bit = EGL_OPENGL_ES2_BIT;
break;
case 3:
bit = EGL_OPENGL_ES3_BIT_KHR;
break;
default:
break;
}
break;
case EGL_OPENVG_API:
bit = EGL_OPENVG_BIT;
break;
case EGL_OPENGL_API:
bit = EGL_OPENGL_BIT;
break;
default:
break;
}
return bit;
}
/**
* Parse the list of context attributes and return the proper error code.
*/
static EGLint
_eglParseContextAttribList(_EGLContext *ctx, _EGLDisplay *dpy,
const EGLint *attrib_list)
{
EGLenum api = ctx->ClientAPI;
EGLint i, err = EGL_SUCCESS;
if (!attrib_list)
return EGL_SUCCESS;
if (api == EGL_OPENVG_API && attrib_list[0] != EGL_NONE) {
_eglLog(_EGL_DEBUG, "bad context attribute 0x%04x", attrib_list[0]);
return EGL_BAD_ATTRIBUTE;
}
for (i = 0; attrib_list[i] != EGL_NONE; i++) {
EGLint attr = attrib_list[i++];
EGLint val = attrib_list[i];
switch (attr) {
case EGL_CONTEXT_CLIENT_VERSION:
ctx->ClientMajorVersion = val;
break;
case EGL_CONTEXT_MINOR_VERSION_KHR:
if (!dpy->Extensions.KHR_create_context) {
err = EGL_BAD_ATTRIBUTE;
break;
}
ctx->ClientMinorVersion = val;
break;
case EGL_CONTEXT_FLAGS_KHR:
if (!dpy->Extensions.KHR_create_context) {
err = EGL_BAD_ATTRIBUTE;
break;
}
/* The EGL_KHR_create_context spec says:
*
* "Flags are only defined for OpenGL context creation, and
* specifying a flags value other than zero for other types of
* contexts, including OpenGL ES contexts, will generate an
* error."
*/
if (api != EGL_OPENGL_API && val != 0) {
err = EGL_BAD_ATTRIBUTE;
break;
}
ctx->Flags = val;
break;
case EGL_CONTEXT_OPENGL_PROFILE_MASK_KHR:
if (!dpy->Extensions.KHR_create_context) {
err = EGL_BAD_ATTRIBUTE;
break;
}
/* The EGL_KHR_create_context spec says:
*
* "[EGL_CONTEXT_OPENGL_PROFILE_MASK_KHR] is only meaningful for
* OpenGL contexts, and specifying it for other types of
* contexts, including OpenGL ES contexts, will generate an
* error."
*/
if (api != EGL_OPENGL_API) {
err = EGL_BAD_ATTRIBUTE;
break;
}
ctx->Profile = val;
break;
case EGL_CONTEXT_OPENGL_RESET_NOTIFICATION_STRATEGY_KHR:
/* The EGL_KHR_create_context spec says:
*
* "[EGL_CONTEXT_OPENGL_RESET_NOTIFICATION_STRATEGY_KHR] is only
* meaningful for OpenGL contexts, and specifying it for other
* types of contexts, including OpenGL ES contexts, will generate
* an error."
*/
if (!dpy->Extensions.KHR_create_context
|| api != EGL_OPENGL_API) {
err = EGL_BAD_ATTRIBUTE;
break;
}
ctx->ResetNotificationStrategy = val;
break;
case EGL_CONTEXT_OPENGL_RESET_NOTIFICATION_STRATEGY_EXT:
/* The EGL_EXT_create_context_robustness spec says:
*
* "[EGL_CONTEXT_OPENGL_RESET_NOTIFICATION_STRATEGY_EXT] is only
* meaningful for OpenGL ES contexts, and specifying it for other
* types of contexts will generate an EGL_BAD_ATTRIBUTE error."
*/
if (!dpy->Extensions.EXT_create_context_robustness
|| api != EGL_OPENGL_ES_API) {
err = EGL_BAD_ATTRIBUTE;
break;
}
ctx->ResetNotificationStrategy = val;
break;
case EGL_CONTEXT_OPENGL_ROBUST_ACCESS_EXT:
if (!dpy->Extensions.EXT_create_context_robustness) {
err = EGL_BAD_ATTRIBUTE;
break;
}
ctx->Flags = EGL_CONTEXT_OPENGL_ROBUST_ACCESS_BIT_KHR;
break;
default:
err = EGL_BAD_ATTRIBUTE;
break;
}
if (err != EGL_SUCCESS) {
_eglLog(_EGL_DEBUG, "bad context attribute 0x%04x", attr);
break;
}
}
if (api == EGL_OPENGL_API) {
/* The EGL_KHR_create_context spec says:
*
* "If the requested OpenGL version is less than 3.2,
* EGL_CONTEXT_OPENGL_PROFILE_MASK_KHR is ignored and the
* functionality of the context is determined solely by the
* requested version."
*
* Since the value is ignored, only validate the setting if the version
* is >= 3.2.
*/
if (ctx->ClientMajorVersion >= 4
|| (ctx->ClientMajorVersion == 3 && ctx->ClientMinorVersion >= 2)) {
switch (ctx->Profile) {
case EGL_CONTEXT_OPENGL_CORE_PROFILE_BIT_KHR:
case EGL_CONTEXT_OPENGL_COMPATIBILITY_PROFILE_BIT_KHR:
break;
default:
/* The EGL_KHR_create_context spec says:
*
* "* If an OpenGL context is requested, the requested version
* is greater than 3.2, and the value for attribute
* EGL_CONTEXT_OPENGL_PROFILE_MASK_KHR has no bits set; has
* any bits set other than EGL_CONTEXT_OPENGL_CORE_PROFILE_BIT_KHR
* and EGL_CONTEXT_OPENGL_COMPATIBILITY_PROFILE_BIT_KHR; has
* more than one of these bits set; or if the implementation does
* not support the requested profile, then an EGL_BAD_MATCH error
* is generated."
*/
err = EGL_BAD_MATCH;
break;
}
}
/* The EGL_KHR_create_context spec says:
*
* "* If an OpenGL context is requested and the values for
* attributes EGL_CONTEXT_MAJOR_VERSION_KHR and
* EGL_CONTEXT_MINOR_VERSION_KHR, when considered together with
* the value for attribute
* EGL_CONTEXT_FORWARD_COMPATIBLE_BIT_KHR, specify an OpenGL
* version and feature set that are not defined, than an
* EGL_BAD_MATCH error is generated.
*
* ... Thus, examples of invalid combinations of attributes
* include:
*
* - Major version < 1 or > 4
* - Major version == 1 and minor version < 0 or > 5
* - Major version == 2 and minor version < 0 or > 1
* - Major version == 3 and minor version < 0 or > 2
* - Major version == 4 and minor version < 0 or > 2
* - Forward-compatible flag set and major version < 3"
*/
if (ctx->ClientMajorVersion < 1 || ctx->ClientMinorVersion < 0)
err = EGL_BAD_MATCH;
switch (ctx->ClientMajorVersion) {
case 1:
if (ctx->ClientMinorVersion > 5
|| (ctx->Flags & EGL_CONTEXT_OPENGL_FORWARD_COMPATIBLE_BIT_KHR) != 0)
err = EGL_BAD_MATCH;
break;
case 2:
if (ctx->ClientMinorVersion > 1
|| (ctx->Flags & EGL_CONTEXT_OPENGL_FORWARD_COMPATIBLE_BIT_KHR) != 0)
err = EGL_BAD_MATCH;
break;
case 3:
/* Note: The text above is incorrect. There *is* an OpenGL 3.3!
*/
if (ctx->ClientMinorVersion > 3)
err = EGL_BAD_MATCH;
break;
case 4:
default:
/* Don't put additional version checks here. We don't know that
* there won't be versions > 4.2.
*/
break;
}
} else if (api == EGL_OPENGL_ES_API) {
/* The EGL_KHR_create_context spec says:
*
* "* If an OpenGL ES context is requested and the values for
* attributes EGL_CONTEXT_MAJOR_VERSION_KHR and
* EGL_CONTEXT_MINOR_VERSION_KHR specify an OpenGL ES version that
* is not defined, than an EGL_BAD_MATCH error is generated.
*
* ... Examples of invalid combinations of attributes include:
*
* - Major version < 1 or > 2
* - Major version == 1 and minor version < 0 or > 1
* - Major version == 2 and minor version != 0
*/
if (ctx->ClientMajorVersion < 1 || ctx->ClientMinorVersion < 0)
err = EGL_BAD_MATCH;
switch (ctx->ClientMajorVersion) {
case 1:
if (ctx->ClientMinorVersion > 1)
err = EGL_BAD_MATCH;
break;
case 2:
if (ctx->ClientMinorVersion > 0)
err = EGL_BAD_MATCH;
break;
case 3:
default:
/* Don't put additional version checks here. We don't know that
* there won't be versions > 3.0.
*/
break;
}
}
switch (ctx->ResetNotificationStrategy) {
case EGL_NO_RESET_NOTIFICATION_KHR:
case EGL_LOSE_CONTEXT_ON_RESET_KHR:
break;
default:
err = EGL_BAD_ATTRIBUTE;
break;
}
if ((ctx->Flags & ~(EGL_CONTEXT_OPENGL_DEBUG_BIT_KHR
| EGL_CONTEXT_OPENGL_FORWARD_COMPATIBLE_BIT_KHR
| EGL_CONTEXT_OPENGL_ROBUST_ACCESS_BIT_KHR)) != 0) {
err = EGL_BAD_ATTRIBUTE;
}
return err;
}
/**
* Initialize the given _EGLContext object to defaults and/or the values
* in the attrib_list.
*/
EGLBoolean
_eglInitContext(_EGLContext *ctx, _EGLDisplay *dpy, _EGLConfig *conf,
const EGLint *attrib_list)
{
const EGLenum api = eglQueryAPI();
EGLint err;
if (api == EGL_NONE) {
_eglError(EGL_BAD_MATCH, "eglCreateContext(no client API)");
return EGL_FALSE;
}
_eglInitResource(&ctx->Resource, sizeof(*ctx), dpy);
ctx->ClientAPI = api;
ctx->Config = conf;
ctx->WindowRenderBuffer = EGL_NONE;
ctx->Profile = EGL_CONTEXT_OPENGL_CORE_PROFILE_BIT_KHR;
ctx->ClientMajorVersion = 1; /* the default, per EGL spec */
ctx->ClientMinorVersion = 0;
ctx->Flags = 0;
ctx->Profile = EGL_CONTEXT_OPENGL_CORE_PROFILE_BIT_KHR;
ctx->ResetNotificationStrategy = EGL_NO_RESET_NOTIFICATION_KHR;
err = _eglParseContextAttribList(ctx, dpy, attrib_list);
if (err == EGL_SUCCESS && ctx->Config) {
EGLint api_bit;
api_bit = _eglGetContextAPIBit(ctx);
if (!(ctx->Config->RenderableType & api_bit)) {
_eglLog(_EGL_DEBUG, "context api is 0x%x while config supports 0x%x",
api_bit, ctx->Config->RenderableType);
err = EGL_BAD_CONFIG;
}
}
if (err != EGL_SUCCESS)
return _eglError(err, "eglCreateContext");
return EGL_TRUE;
}
static EGLint
_eglQueryContextRenderBuffer(_EGLContext *ctx)
{
_EGLSurface *surf = ctx->DrawSurface;
EGLint rb;
if (!surf)
return EGL_NONE;
if (surf->Type == EGL_WINDOW_BIT && ctx->WindowRenderBuffer != EGL_NONE)
rb = ctx->WindowRenderBuffer;
else
rb = surf->RenderBuffer;
return rb;
}
EGLBoolean
_eglQueryContext(_EGLDriver *drv, _EGLDisplay *dpy, _EGLContext *c,
EGLint attribute, EGLint *value)
{
(void) drv;
(void) dpy;
if (!value)
return _eglError(EGL_BAD_PARAMETER, "eglQueryContext");
switch (attribute) {
case EGL_CONFIG_ID:
if (!c->Config)
return _eglError(EGL_BAD_ATTRIBUTE, "eglQueryContext");
*value = c->Config->ConfigID;
break;
case EGL_CONTEXT_CLIENT_VERSION:
*value = c->ClientMajorVersion;
break;
case EGL_CONTEXT_CLIENT_TYPE:
*value = c->ClientAPI;
break;
case EGL_RENDER_BUFFER:
*value = _eglQueryContextRenderBuffer(c);
break;
default:
return _eglError(EGL_BAD_ATTRIBUTE, "eglQueryContext");
}
return EGL_TRUE;
}
/**
* Bind the context to the thread and return the previous context.
*
* Note that the context may be NULL.
*/
static _EGLContext *
_eglBindContextToThread(_EGLContext *ctx, _EGLThreadInfo *t)
{
EGLint apiIndex;
_EGLContext *oldCtx;
apiIndex = (ctx) ?
_eglConvertApiToIndex(ctx->ClientAPI) : t->CurrentAPIIndex;
oldCtx = t->CurrentContexts[apiIndex];
if (ctx != oldCtx) {
if (oldCtx)
oldCtx->Binding = NULL;
if (ctx)
ctx->Binding = t;
t->CurrentContexts[apiIndex] = ctx;
}
return oldCtx;
}
/**
* Return true if the given context and surfaces can be made current.
*/
static EGLBoolean
_eglCheckMakeCurrent(_EGLContext *ctx, _EGLSurface *draw, _EGLSurface *read)
{
_EGLThreadInfo *t = _eglGetCurrentThread();
_EGLDisplay *dpy;
EGLint conflict_api;
if (_eglIsCurrentThreadDummy())
return _eglError(EGL_BAD_ALLOC, "eglMakeCurrent");
/* this is easy */
if (!ctx) {
if (draw || read)
return _eglError(EGL_BAD_MATCH, "eglMakeCurrent");
return EGL_TRUE;
}
dpy = ctx->Resource.Display;
if (!dpy->Extensions.KHR_surfaceless_context
&& (draw == NULL || read == NULL))
return _eglError(EGL_BAD_MATCH, "eglMakeCurrent");
/*
* The spec says
*
* "If ctx is current to some other thread, or if either draw or read are
* bound to contexts in another thread, an EGL_BAD_ACCESS error is
* generated."
*
* and
*
* "at most one context may be bound to a particular surface at a given
* time"
*/
if (ctx->Binding && ctx->Binding != t)
return _eglError(EGL_BAD_ACCESS, "eglMakeCurrent");
if (draw && draw->CurrentContext && draw->CurrentContext != ctx) {
if (draw->CurrentContext->Binding != t ||
draw->CurrentContext->ClientAPI != ctx->ClientAPI)
return _eglError(EGL_BAD_ACCESS, "eglMakeCurrent");
}
if (read && read->CurrentContext && read->CurrentContext != ctx) {
if (read->CurrentContext->Binding != t ||
read->CurrentContext->ClientAPI != ctx->ClientAPI)
return _eglError(EGL_BAD_ACCESS, "eglMakeCurrent");
}
/* simply require the configs to be equal */
if ((draw && draw->Config != ctx->Config) ||
(read && read->Config != ctx->Config))
return _eglError(EGL_BAD_MATCH, "eglMakeCurrent");
switch (ctx->ClientAPI) {
/* OpenGL and OpenGL ES are conflicting */
case EGL_OPENGL_ES_API:
conflict_api = EGL_OPENGL_API;
break;
case EGL_OPENGL_API:
conflict_api = EGL_OPENGL_ES_API;
break;
default:
conflict_api = -1;
break;
}
if (conflict_api >= 0 && _eglGetAPIContext(conflict_api))
return _eglError(EGL_BAD_ACCESS, "eglMakeCurrent");
return EGL_TRUE;
}
/**
* Bind the context to the current thread and given surfaces. Return the
* previous bound context and surfaces. The caller should unreference the
* returned context and surfaces.
*
* Making a second call with the resources returned by the first call
* unsurprisingly undoes the first call, except for the resouce reference
* counts.
*/
EGLBoolean
_eglBindContext(_EGLContext *ctx, _EGLSurface *draw, _EGLSurface *read,
_EGLContext **old_ctx,
_EGLSurface **old_draw, _EGLSurface **old_read)
{
_EGLThreadInfo *t = _eglGetCurrentThread();
_EGLContext *prev_ctx;
_EGLSurface *prev_draw, *prev_read;
printf("%s\n",__FUNCTION__);
if (!_eglCheckMakeCurrent(ctx, draw, read))
return EGL_FALSE;
/* increment refcounts before binding */
_eglGetContext(ctx);
_eglGetSurface(draw);
_eglGetSurface(read);
/* bind the new context */
prev_ctx = _eglBindContextToThread(ctx, t);
/* break previous bindings */
if (prev_ctx) {
prev_draw = prev_ctx->DrawSurface;
prev_read = prev_ctx->ReadSurface;
if (prev_draw)
prev_draw->CurrentContext = NULL;
if (prev_read)
prev_read->CurrentContext = NULL;
prev_ctx->DrawSurface = NULL;
prev_ctx->ReadSurface = NULL;
}
else {
prev_draw = prev_read = NULL;
}
/* establish new bindings */
if (ctx) {
if (draw)
draw->CurrentContext = ctx;
if (read)
read->CurrentContext = ctx;
ctx->DrawSurface = draw;
ctx->ReadSurface = read;
}
assert(old_ctx && old_draw && old_read);
*old_ctx = prev_ctx;
*old_draw = prev_draw;
*old_read = prev_read;
printf("leave %s\n",__FUNCTION__);
return EGL_TRUE;
}

View File

@ -1,395 +0,0 @@
/**************************************************************************
*
* Copyright 2008 Tungsten Graphics, Inc., Cedar Park, Texas.
* Copyright 2009-2010 Chia-I Wu <olvaffe@gmail.com>
* Copyright 2010-2011 LunarG, 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, sub license, 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 (including the
* next paragraph) 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.
*
**************************************************************************/
/**
* Functions related to EGLDisplay.
*/
#include <assert.h>
#include <stdlib.h>
#include <string.h>
#include "eglcontext.h"
#include "eglsurface.h"
#include "egldisplay.h"
#include "egldriver.h"
#include "eglglobals.h"
#include "eglmutex.h"
#include "egllog.h"
/* Includes for _eglNativePlatformDetectNativeDisplay */
#ifdef HAVE_MINCORE
#include <unistd.h>
#include <sys/mman.h>
#endif
#ifdef HAVE_WAYLAND_PLATFORM
#include <wayland-client.h>
#endif
#ifdef HAVE_DRM_PLATFORM
#include <gbm.h>
#endif
#ifdef HAVE_FBDEV_PLATFORM
#include <stdint.h>
#include <sys/types.h>
#include <sys/stat.h>
#endif
/**
* Map --with-egl-platforms names to platform types.
*/
static const struct {
_EGLPlatformType platform;
const char *name;
} egl_platforms[_EGL_NUM_PLATFORMS] = {
{ _EGL_PLATFORM_DRM, "drm" }
};
/**
* Return the native platform by parsing EGL_PLATFORM.
*/
static _EGLPlatformType
_eglGetNativePlatformFromEnv(void)
{
_EGLPlatformType plat = _EGL_INVALID_PLATFORM;
const char *plat_name;
EGLint i;
plat_name = getenv("EGL_PLATFORM");
/* try deprecated env variable */
if (!plat_name || !plat_name[0])
plat_name = getenv("EGL_DISPLAY");
if (!plat_name || !plat_name[0])
return _EGL_INVALID_PLATFORM;
for (i = 0; i < _EGL_NUM_PLATFORMS; i++) {
if (strcmp(egl_platforms[i].name, plat_name) == 0) {
plat = egl_platforms[i].platform;
break;
}
}
return plat;
}
/**
* Perform validity checks on a generic pointer.
*/
static EGLBoolean
_eglPointerIsDereferencable(void *p)
{
#ifdef HAVE_MINCORE
uintptr_t addr = (uintptr_t) p;
unsigned char valid = 0;
const long page_size = getpagesize();
if (p == NULL)
return EGL_FALSE;
/* align addr to page_size */
addr &= ~(page_size - 1);
if (mincore((void *) addr, page_size, &valid) < 0) {
_eglLog(_EGL_DEBUG, "mincore failed: %m");
return EGL_FALSE;
}
return (valid & 0x01) == 0x01;
#else
return p != NULL;
#endif
}
/**
* Try detecting native platform with the help of native display characteristcs.
*/
static _EGLPlatformType
_eglNativePlatformDetectNativeDisplay(EGLNativeDisplayType nativeDisplay)
{
return _EGL_PLATFORM_DRM;
}
/**
* Return the native platform. It is the platform of the EGL native types.
*/
_EGLPlatformType
_eglGetNativePlatform(EGLNativeDisplayType nativeDisplay)
{
return _EGL_PLATFORM_DRM;
}
/**
* Finish display management.
*/
void
_eglFiniDisplay(void)
{
_EGLDisplay *dpyList, *dpy;
/* atexit function is called with global mutex locked */
dpyList = _eglGlobal.DisplayList;
while (dpyList) {
EGLint i;
/* pop list head */
dpy = dpyList;
dpyList = dpyList->Next;
for (i = 0; i < _EGL_NUM_RESOURCES; i++) {
if (dpy->ResourceLists[i]) {
_eglLog(_EGL_DEBUG, "Display %p is destroyed with resources", dpy);
break;
}
}
free(dpy);
}
_eglGlobal.DisplayList = NULL;
}
/**
* Find the display corresponding to the specified native display, or create a
* new one.
*/
_EGLDisplay *
_eglFindDisplay(_EGLPlatformType plat, void *plat_dpy)
{
_EGLDisplay *dpy;
if (plat == _EGL_INVALID_PLATFORM)
return NULL;
_eglLockMutex(_eglGlobal.Mutex);
/* search the display list first */
dpy = _eglGlobal.DisplayList;
while (dpy) {
if (dpy->Platform == plat && dpy->PlatformDisplay == plat_dpy)
break;
dpy = dpy->Next;
}
/* create a new display */
if (!dpy) {
dpy = calloc(1, sizeof(_EGLDisplay));
if (dpy) {
_eglInitMutex(&dpy->Mutex);
dpy->Platform = plat;
dpy->PlatformDisplay = plat_dpy;
/* add to the display list */
dpy->Next = _eglGlobal.DisplayList;
_eglGlobal.DisplayList = dpy;
}
}
_eglUnlockMutex(_eglGlobal.Mutex);
return dpy;
}
/**
* Destroy the contexts and surfaces that are linked to the display.
*/
void
_eglReleaseDisplayResources(_EGLDriver *drv, _EGLDisplay *display)
{
_EGLResource *list;
list = display->ResourceLists[_EGL_RESOURCE_CONTEXT];
while (list) {
_EGLContext *ctx = (_EGLContext *) list;
list = list->Next;
_eglUnlinkContext(ctx);
drv->API.DestroyContext(drv, display, ctx);
}
assert(!display->ResourceLists[_EGL_RESOURCE_CONTEXT]);
list = display->ResourceLists[_EGL_RESOURCE_SURFACE];
while (list) {
_EGLSurface *surf = (_EGLSurface *) list;
list = list->Next;
_eglUnlinkSurface(surf);
drv->API.DestroySurface(drv, display, surf);
}
assert(!display->ResourceLists[_EGL_RESOURCE_SURFACE]);
}
/**
* Free all the data hanging of an _EGLDisplay object, but not
* the object itself.
*/
void
_eglCleanupDisplay(_EGLDisplay *disp)
{
if (disp->Configs) {
_eglDestroyArray(disp->Configs, free);
disp->Configs = NULL;
}
/* XXX incomplete */
}
/**
* Return EGL_TRUE if the given handle is a valid handle to a display.
*/
EGLBoolean
_eglCheckDisplayHandle(EGLDisplay dpy)
{
_EGLDisplay *cur;
_eglLockMutex(_eglGlobal.Mutex);
cur = _eglGlobal.DisplayList;
while (cur) {
if (cur == (_EGLDisplay *) dpy)
break;
cur = cur->Next;
}
_eglUnlockMutex(_eglGlobal.Mutex);
return (cur != NULL);
}
/**
* Return EGL_TRUE if the given resource is valid. That is, the display does
* own the resource.
*/
EGLBoolean
_eglCheckResource(void *res, _EGLResourceType type, _EGLDisplay *dpy)
{
_EGLResource *list = dpy->ResourceLists[type];
if (!res)
return EGL_FALSE;
while (list) {
if (res == (void *) list) {
assert(list->Display == dpy);
break;
}
list = list->Next;
}
return (list != NULL);
}
/**
* Initialize a display resource.
*/
void
_eglInitResource(_EGLResource *res, EGLint size, _EGLDisplay *dpy)
{
memset(res, 0, size);
res->Display = dpy;
res->RefCount = 1;
}
/**
* Increment reference count for the resource.
*/
void
_eglGetResource(_EGLResource *res)
{
assert(res && res->RefCount > 0);
/* hopefully a resource is always manipulated with its display locked */
res->RefCount++;
}
/**
* Decrement reference count for the resource.
*/
EGLBoolean
_eglPutResource(_EGLResource *res)
{
assert(res && res->RefCount > 0);
res->RefCount--;
return (!res->RefCount);
}
/**
* Link a resource to its display.
*/
void
_eglLinkResource(_EGLResource *res, _EGLResourceType type)
{
assert(res->Display);
printf("%s Resource: %p\n", __FUNCTION__, res);
res->IsLinked = EGL_TRUE;
res->Next = res->Display->ResourceLists[type];
res->Display->ResourceLists[type] = res;
_eglGetResource(res);
}
/**
* Unlink a linked resource from its display.
*/
void
_eglUnlinkResource(_EGLResource *res, _EGLResourceType type)
{
_EGLResource *prev;
prev = res->Display->ResourceLists[type];
if (prev != res) {
while (prev) {
if (prev->Next == res)
break;
prev = prev->Next;
}
assert(prev);
prev->Next = res->Next;
}
else {
res->Display->ResourceLists[type] = res->Next;
}
res->Next = NULL;
res->IsLinked = EGL_FALSE;
_eglPutResource(res);
/* We always unlink before destroy. The driver still owns a reference */
assert(res->RefCount);
}

View File

@ -1,689 +0,0 @@
/**************************************************************************
*
* Copyright 2008 Tungsten Graphics, Inc., Cedar Park, Texas.
* Copyright 2009-2010 Chia-I Wu <olvaffe@gmail.com>
* Copyright 2010-2011 LunarG, 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, sub license, 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 (including the
* next paragraph) 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.
*
**************************************************************************/
/**
* Functions for choosing and opening/loading device drivers.
*/
#include <assert.h>
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
#include "eglstring.h"
#include "egldefines.h"
#include "egldisplay.h"
#include "egldriver.h"
#include "egllog.h"
#include "eglmutex.h"
typedef unsigned int lib_handle;
lib_handle load_library(const char *name);
void *get_proc_address(lib_handle lib, char *proc_name);
typedef struct _egl_module {
char *Path;
_EGLMain_t BuiltIn;
void *Handle;
_EGLDriver *Driver;
} _EGLModule;
static _EGL_DECLARE_MUTEX(_eglModuleMutex);
static _EGLArray *_eglModules;
const struct {
const char *name;
_EGLMain_t main;
} _eglBuiltInDrivers[] = {
#ifdef _EGL_BUILT_IN_DRIVER_GALLIUM
{ "egl_gallium", _eglBuiltInDriverGALLIUM },
#endif
#ifdef _EGL_BUILT_IN_DRIVER_DRI2
{ "egl_dri2", _eglBuiltInDriverDRI2 },
#endif
#ifdef _EGL_BUILT_IN_DRIVER_GLX
{ "egl_glx", _eglBuiltInDriverGLX },
#endif
{ NULL, NULL }
};
/**
* Wrappers for dlopen/dlclose()
*/
#if defined(_EGL_OS_WINDOWS)
typedef HMODULE lib_handle;
static HMODULE
open_library(const char *filename)
{
return LoadLibrary(filename);
}
static void
close_library(HMODULE lib)
{
FreeLibrary(lib);
}
static const char *
library_suffix(void)
{
return ".dll";
}
#elif defined(_EGL_OS_UNIX)
typedef void * lib_handle;
static void *
open_library(const char *filename)
{
return dlopen(filename, RTLD_LAZY);
}
static void
close_library(void *lib)
{
dlclose(lib);
}
static const char *
library_suffix(void)
{
return ".so";
}
#endif
/**
* Open the named driver and find its bootstrap function: _eglMain().
*/
static _EGLMain_t
_eglOpenLibrary(const char *driverPath, lib_handle *handle)
{
lib_handle lib;
_EGLMain_t mainFunc = NULL;
const char *error = "unknown error";
assert(driverPath);
_eglLog(_EGL_DEBUG, "dlopen(%s)", driverPath);
lib = load_library(driverPath);
if (!lib) {
_eglLog(_EGL_WARNING, "Could not open driver %s (%s)",
driverPath, error);
return NULL;
}
mainFunc = (_EGLMain_t) get_proc_address(lib, "_eglMain");
if (!mainFunc) {
_eglLog(_EGL_WARNING, "_eglMain not found in %s (%s)",
driverPath, error);
return NULL;
}
*handle = lib;
return mainFunc;
}
/**
* Load a module and create the driver object.
*/
static EGLBoolean
_eglLoadModule(_EGLModule *mod)
{
_EGLMain_t mainFunc;
lib_handle lib;
_EGLDriver *drv;
if (mod->Driver)
return EGL_TRUE;
if (mod->BuiltIn) {
lib = (lib_handle) NULL;
mainFunc = mod->BuiltIn;
}
else {
mainFunc = _eglOpenLibrary(mod->Path, &lib);
if (!mainFunc)
return EGL_FALSE;
}
drv = mainFunc(NULL);
if (!drv) {
return EGL_FALSE;
}
if (!drv->Name) {
_eglLog(_EGL_WARNING, "Driver loaded from %s has no name", mod->Path);
drv->Name = "UNNAMED";
}
mod->Handle = (void *) lib;
mod->Driver = drv;
return EGL_TRUE;
}
/**
* Unload a module.
*/
static void
_eglUnloadModule(_EGLModule *mod)
{
#if defined(_EGL_OS_UNIX)
/* destroy the driver */
if (mod->Driver && mod->Driver->Unload)
mod->Driver->Unload(mod->Driver);
/*
* XXX At this point (atexit), the module might be the last reference to
* libEGL. Closing the module might unmap libEGL and give problems.
*/
#if 0
if (mod->Handle)
close_library(mod->Handle);
#endif
#elif defined(_EGL_OS_WINDOWS)
/* XXX Windows unloads DLLs before atexit */
#endif
mod->Driver = NULL;
mod->Handle = NULL;
}
/**
* Add a module to the module array.
*/
static _EGLModule *
_eglAddModule(const char *path)
{
_EGLModule *mod;
EGLint i;
if (!_eglModules) {
_eglModules = _eglCreateArray("Module", 8);
if (!_eglModules)
return NULL;
}
/* find duplicates */
for (i = 0; i < _eglModules->Size; i++) {
mod = _eglModules->Elements[i];
if (strcmp(mod->Path, path) == 0)
return mod;
}
/* allocate a new one */
mod = calloc(1, sizeof(*mod));
if (mod) {
mod->Path = _eglstrdup(path);
if (!mod->Path) {
free(mod);
mod = NULL;
}
}
if (mod) {
_eglAppendArray(_eglModules, (void *) mod);
_eglLog(_EGL_DEBUG, "added %s to module array", mod->Path);
}
return mod;
}
/**
* Free a module.
*/
static void
_eglFreeModule(void *module)
{
_EGLModule *mod = (_EGLModule *) module;
_eglUnloadModule(mod);
free(mod->Path);
free(mod);
}
#if 0
/**
* A loader function for use with _eglPreloadForEach. The loader data is the
* filename of the driver. This function stops on the first valid driver.
*/
static EGLBoolean
_eglLoaderFile(const char *dir, size_t len, void *loader_data)
{
char path[1024];
const char *filename = (const char *) loader_data;
size_t flen = strlen(filename);
/* make a full path */
if (len + flen + 2 > sizeof(path))
return EGL_TRUE;
if (len) {
memcpy(path, dir, len);
path[len++] = '/';
}
memcpy(path + len, filename, flen);
len += flen;
path[len] = '\0';
if (library_suffix()) {
const char *suffix = library_suffix();
size_t slen = strlen(suffix);
const char *p;
EGLBoolean need_suffix;
p = filename + flen - slen;
need_suffix = (p < filename || strcmp(p, suffix) != 0);
if (need_suffix) {
/* overflow */
if (len + slen + 1 > sizeof(path))
return EGL_TRUE;
strcpy(path + len, suffix);
}
}
#if defined(_EGL_OS_UNIX)
/* check if the file exists */
if (access(path, F_OK))
return EGL_TRUE;
#endif
_eglAddModule(path);
return EGL_TRUE;
}
/**
* Run the callback function on each driver directory.
*
* The process may end prematurely if the callback function returns false.
*/
static void
_eglPreloadForEach(const char *search_path,
EGLBoolean (*loader)(const char *, size_t, void *),
void *loader_data)
{
const char *cur, *next;
size_t len;
cur = search_path;
while (cur) {
next = strchr(cur, ':');
len = (next) ? next - cur : strlen(cur);
if (!loader(cur, len, loader_data))
break;
cur = (next) ? next + 1 : NULL;
}
}
/**
* Return a list of colon-separated driver directories.
*/
static const char *
_eglGetSearchPath(void)
{
static char search_path[1024];
#if defined(_EGL_OS_UNIX) || defined(_EGL_OS_WINDOWS)
if (search_path[0] == '\0') {
char *buf = search_path;
size_t len = sizeof(search_path);
EGLBoolean use_env;
char dir_sep;
int ret;
#if defined(_EGL_OS_UNIX)
use_env = (geteuid() == getuid() && getegid() == getgid());
dir_sep = '/';
#else
use_env = EGL_TRUE;
dir_sep = '\\';
#endif
if (use_env) {
char *p;
/* extract the dirname from EGL_DRIVER */
p = getenv("EGL_DRIVER");
if (p && strchr(p, dir_sep)) {
ret = _eglsnprintf(buf, len, "%s", p);
if (ret > 0 && ret < len) {
p = strrchr(buf, dir_sep);
*p++ = ':';
len -= p - buf;
buf = p;
}
}
/* append EGL_DRIVERS_PATH */
p = getenv("EGL_DRIVERS_PATH");
if (p) {
ret = _eglsnprintf(buf, len, "%s:", p);
if (ret > 0 && ret < len) {
buf += ret;
len -= ret;
}
}
}
else {
_eglLog(_EGL_DEBUG,
"ignore EGL_DRIVERS_PATH for setuid/setgid binaries");
}
ret = _eglsnprintf(buf, len, "%s", _EGL_DRIVER_SEARCH_DIR);
if (ret < 0 || ret >= len)
search_path[0] = '\0';
_eglLog(_EGL_DEBUG, "EGL search path is %s", search_path);
}
#endif /* defined(_EGL_OS_UNIX) || defined(_EGL_OS_WINDOWS) */
return search_path;
}
/**
* Add the user driver to the module array.
*
* The user driver is specified by EGL_DRIVER.
*/
static EGLBoolean
_eglAddUserDriver(void)
{
const char *search_path = _eglGetSearchPath();
char *env;
size_t name_len = 0;
env = getenv("EGL_DRIVER");
#if defined(_EGL_OS_UNIX)
if (env && strchr(env, '/')) {
search_path = "";
if ((geteuid() != getuid() || getegid() != getgid())) {
_eglLog(_EGL_DEBUG,
"ignore EGL_DRIVER for setuid/setgid binaries");
env = NULL;
}
}
else if (env) {
char *suffix = strchr(env, '.');
name_len = (suffix) ? suffix - env : strlen(env);
}
#else
if (env)
name_len = strlen(env);
#endif /* _EGL_OS_UNIX */
/*
* Try built-in drivers first if we know the driver name. This makes sure
* we do not load the outdated external driver that is still on the
* filesystem.
*/
if (name_len) {
_EGLModule *mod;
EGLint i;
for (i = 0; _eglBuiltInDrivers[i].name; i++) {
if (strlen(_eglBuiltInDrivers[i].name) == name_len &&
!strncmp(_eglBuiltInDrivers[i].name, env, name_len)) {
mod = _eglAddModule(env);
if (mod)
mod->BuiltIn = _eglBuiltInDrivers[i].main;
return EGL_TRUE;
}
}
}
/* otherwise, treat env as a path */
if (env) {
_eglPreloadForEach(search_path, _eglLoaderFile, (void *) env);
return EGL_TRUE;
}
return EGL_FALSE;
}
/**
* Add egl_gallium to the module array.
*/
static void
_eglAddGalliumDriver(void)
{
#ifndef _EGL_BUILT_IN_DRIVER_GALLIUM
void *external = (void *) "egl_gallium";
_eglPreloadForEach(_eglGetSearchPath(), _eglLoaderFile, external);
#endif
}
#endif
/**
* Add built-in drivers to the module array.
*/
static void
_eglAddBuiltInDrivers(void)
{
_EGLModule *mod;
EGLint i;
for (i = 0; _eglBuiltInDrivers[i].name; i++) {
mod = _eglAddModule(_eglBuiltInDrivers[i].name);
if (mod)
mod->BuiltIn = _eglBuiltInDrivers[i].main;
}
}
/**
* Add drivers to the module array. Drivers will be loaded as they are matched
* to displays.
*/
static EGLBoolean
_eglAddDrivers(void)
{
if (_eglModules)
return EGL_TRUE;
// if (!_eglAddUserDriver()) {
/*
* Add other drivers only when EGL_DRIVER is not set. The order here
* decides the priorities.
*/
// _eglAddGalliumDriver();
_eglAddBuiltInDrivers();
// }
return (_eglModules != NULL);
}
/**
* A helper function for _eglMatchDriver. It finds the first driver that can
* initialize the display and return.
*/
static _EGLDriver *
_eglMatchAndInitialize(_EGLDisplay *dpy)
{
_EGLDriver *drv = NULL;
EGLint i = 0;
if (!_eglAddDrivers()) {
_eglLog(_EGL_WARNING, "failed to find any driver");
return NULL;
}
if (dpy->Driver) {
drv = dpy->Driver;
/* no re-matching? */
if (!drv->API.Initialize(drv, dpy))
drv = NULL;
return drv;
}
while (i < _eglModules->Size) {
_EGLModule *mod = (_EGLModule *) _eglModules->Elements[i];
if (!_eglLoadModule(mod)) {
/* remove invalid modules */
_eglEraseArray(_eglModules, i, _eglFreeModule);
continue;
}
if (mod->Driver->API.Initialize(mod->Driver, dpy)) {
drv = mod->Driver;
break;
}
else {
i++;
}
}
return drv;
}
/**
* Match a display to a driver. The display is initialized unless test_only is
* true. The matching is done by finding the first driver that can initialize
* the display.
*/
_EGLDriver *
_eglMatchDriver(_EGLDisplay *dpy, EGLBoolean test_only)
{
_EGLDriver *best_drv;
assert(!dpy->Initialized);
_eglLockMutex(&_eglModuleMutex);
/* set options */
dpy->Options.TestOnly = test_only;
dpy->Options.UseFallback = EGL_FALSE;
best_drv = _eglMatchAndInitialize(dpy);
if (!best_drv) {
dpy->Options.UseFallback = EGL_TRUE;
best_drv = _eglMatchAndInitialize(dpy);
}
_eglUnlockMutex(&_eglModuleMutex);
if (best_drv) {
_eglLog(_EGL_DEBUG, "the best driver is %s%s",
best_drv->Name, (test_only) ? " (test only) " : "");
if (!test_only) {
dpy->Driver = best_drv;
dpy->Initialized = EGL_TRUE;
}
}
return best_drv;
}
__eglMustCastToProperFunctionPointerType
_eglGetDriverProc(const char *procname)
{
EGLint i;
_EGLProc proc = NULL;
if (!_eglModules) {
/* load the driver for the default display */
EGLDisplay egldpy = eglGetDisplay(EGL_DEFAULT_DISPLAY);
_EGLDisplay *dpy = _eglLookupDisplay(egldpy);
if (!dpy || !_eglMatchDriver(dpy, EGL_TRUE))
return NULL;
}
for (i = 0; i < _eglModules->Size; i++) {
_EGLModule *mod = (_EGLModule *) _eglModules->Elements[i];
if (!mod->Driver)
break;
proc = mod->Driver->API.GetProcAddress(mod->Driver, procname);
if (proc)
break;
}
return proc;
}
/**
* Unload all drivers.
*/
void
_eglUnloadDrivers(void)
{
/* this is called at atexit time */
if (_eglModules) {
_eglDestroyArray(_eglModules, _eglFreeModule);
_eglModules = NULL;
}
}
#if 0
/**
* Invoke a callback function on each EGL search path.
*
* The first argument of the callback function is the name of the search path.
* The second argument is the length of the name.
*/
void
_eglSearchPathForEach(EGLBoolean (*callback)(const char *, size_t, void *),
void *callback_data)
{
const char *search_path = _eglGetSearchPath();
_eglPreloadForEach(search_path, callback, callback_data);
}
#endif

View File

@ -1,240 +0,0 @@
/**************************************************************************
*
* Copyright 2008 Tungsten Graphics, Inc., Cedar Park, Texas.
* Copyright 2009-2010 Chia-I Wu <olvaffe@gmail.com>
* Copyright 2010 LunarG, 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, sub license, 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 (including the
* next paragraph) 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.
*
**************************************************************************/
/*
* Ideas for screen management extension to EGL.
*
* Each EGLDisplay has one or more screens (CRTs, Flat Panels, etc).
* The screens' handles can be obtained with eglGetScreensMESA().
*
* A new kind of EGLSurface is possible- one which can be directly scanned
* out on a screen. Such a surface is created with eglCreateScreenSurface().
*
* To actually display a screen surface on a screen, the eglShowSurface()
* function is called.
*/
#include <assert.h>
#include <stdlib.h>
#include <string.h>
#define EGL_EGLEXT_PROTOTYPES
#include <EGL/egl.h>
#include <EGL/eglext.h>
#include "egldisplay.h"
#include "eglcurrent.h"
#include "eglmode.h"
#include "eglsurface.h"
#include "eglscreen.h"
#include "eglmutex.h"
//#define EGL_MESA_screen_surface
#ifdef EGL_MESA_screen_surface
/* ugh, no atomic op? */
static _EGL_DECLARE_MUTEX(_eglNextScreenHandleMutex);
static EGLScreenMESA _eglNextScreenHandle = 1;
/**
* Return a new screen handle/ID.
* NOTE: we never reuse these!
*/
static EGLScreenMESA
_eglAllocScreenHandle(void)
{
EGLScreenMESA s;
_eglLockMutex(&_eglNextScreenHandleMutex);
s = _eglNextScreenHandle;
_eglNextScreenHandle += _EGL_SCREEN_MAX_MODES;
_eglUnlockMutex(&_eglNextScreenHandleMutex);
return s;
}
/**
* Initialize an _EGLScreen object to default values.
*/
void
_eglInitScreen(_EGLScreen *screen, _EGLDisplay *dpy, EGLint num_modes)
{
memset(screen, 0, sizeof(_EGLScreen));
screen->Display = dpy;
screen->NumModes = num_modes;
screen->StepX = 1;
screen->StepY = 1;
if (num_modes > _EGL_SCREEN_MAX_MODES)
num_modes = _EGL_SCREEN_MAX_MODES;
screen->Modes = calloc(num_modes, sizeof(*screen->Modes));
screen->NumModes = (screen->Modes) ? num_modes : 0;
}
/**
* Link a screen to its display and return the handle of the link.
* The handle can be passed to client directly.
*/
EGLScreenMESA
_eglLinkScreen(_EGLScreen *screen)
{
_EGLDisplay *display;
EGLint i;
assert(screen && screen->Display);
display = screen->Display;
if (!display->Screens) {
display->Screens = _eglCreateArray("Screen", 4);
if (!display->Screens)
return (EGLScreenMESA) 0;
}
screen->Handle = _eglAllocScreenHandle();
for (i = 0; i < screen->NumModes; i++)
screen->Modes[i].Handle = screen->Handle + i;
_eglAppendArray(display->Screens, (void *) screen);
return screen->Handle;
}
/**
* Lookup a handle to find the linked config.
* Return NULL if the handle has no corresponding linked config.
*/
_EGLScreen *
_eglLookupScreen(EGLScreenMESA screen, _EGLDisplay *display)
{
EGLint i;
if (!display || !display->Screens)
return NULL;
for (i = 0; i < display->Screens->Size; i++) {
_EGLScreen *scr = (_EGLScreen *) display->Screens->Elements[i];
if (scr->Handle == screen) {
assert(scr->Display == display);
return scr;
}
}
return NULL;
}
static EGLBoolean
_eglFlattenScreen(void *elem, void *buffer)
{
_EGLScreen *scr = (_EGLScreen *) elem;
EGLScreenMESA *handle = (EGLScreenMESA *) buffer;
*handle = _eglGetScreenHandle(scr);
return EGL_TRUE;
}
EGLBoolean
_eglGetScreensMESA(_EGLDriver *drv, _EGLDisplay *display, EGLScreenMESA *screens,
EGLint max_screens, EGLint *num_screens)
{
*num_screens = _eglFlattenArray(display->Screens, (void *) screens,
sizeof(screens[0]), max_screens, _eglFlattenScreen);
return EGL_TRUE;
}
/**
* Set a screen's surface origin.
*/
EGLBoolean
_eglScreenPositionMESA(_EGLDriver *drv, _EGLDisplay *dpy,
_EGLScreen *scrn, EGLint x, EGLint y)
{
scrn->OriginX = x;
scrn->OriginY = y;
return EGL_TRUE;
}
/**
* Query a screen's current surface.
*/
EGLBoolean
_eglQueryScreenSurfaceMESA(_EGLDriver *drv, _EGLDisplay *dpy,
_EGLScreen *scrn, _EGLSurface **surf)
{
*surf = scrn->CurrentSurface;
return EGL_TRUE;
}
/**
* Query a screen's current mode.
*/
EGLBoolean
_eglQueryScreenModeMESA(_EGLDriver *drv, _EGLDisplay *dpy, _EGLScreen *scrn,
_EGLMode **m)
{
*m = scrn->CurrentMode;
return EGL_TRUE;
}
EGLBoolean
_eglQueryScreenMESA(_EGLDriver *drv, _EGLDisplay *dpy, _EGLScreen *scrn,
EGLint attribute, EGLint *value)
{
switch (attribute) {
case EGL_SCREEN_POSITION_MESA:
value[0] = scrn->OriginX;
value[1] = scrn->OriginY;
break;
case EGL_SCREEN_POSITION_GRANULARITY_MESA:
value[0] = scrn->StepX;
value[1] = scrn->StepY;
break;
default:
_eglError(EGL_BAD_ATTRIBUTE, "eglQueryScreenMESA");
return EGL_FALSE;
}
return EGL_TRUE;
}
#endif /* EGL_MESA_screen_surface */

View File

@ -1,543 +0,0 @@
/**************************************************************************
*
* Copyright 2008 Tungsten Graphics, Inc., Cedar Park, Texas.
* Copyright 2009-2010 Chia-I Wu <olvaffe@gmail.com>
* Copyright 2010 LunarG, 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, sub license, 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 (including the
* next paragraph) 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.
*
**************************************************************************/
/**
* Surface-related functions.
*/
#include <assert.h>
#include <stdlib.h>
#include <string.h>
#include "egldisplay.h"
#include "egldriver.h"
#include "eglcontext.h"
#include "eglconfig.h"
#include "eglcurrent.h"
#include "egllog.h"
#include "eglsurface.h"
static void
_eglClampSwapInterval(_EGLSurface *surf, EGLint interval)
{
EGLint bound = surf->Config->MaxSwapInterval;
if (interval >= bound) {
interval = bound;
}
else {
bound = surf->Config->MinSwapInterval;
if (interval < bound)
interval = bound;
}
surf->SwapInterval = interval;
}
#ifdef EGL_MESA_screen_surface
static EGLint
_eglParseScreenSurfaceAttribList(_EGLSurface *surf, const EGLint *attrib_list)
{
EGLint i, err = EGL_SUCCESS;
if (!attrib_list)
return EGL_SUCCESS;
for (i = 0; attrib_list[i] != EGL_NONE; i++) {
EGLint attr = attrib_list[i++];
EGLint val = attrib_list[i];
switch (attr) {
case EGL_WIDTH:
if (val < 0) {
err = EGL_BAD_PARAMETER;
break;
}
surf->Width = val;
break;
case EGL_HEIGHT:
if (val < 0) {
err = EGL_BAD_PARAMETER;
break;
}
surf->Height = val;
break;
default:
err = EGL_BAD_ATTRIBUTE;
break;
}
if (err != EGL_SUCCESS) {
_eglLog(_EGL_WARNING, "bad surface attribute 0x%04x", attr);
break;
}
}
return err;
}
#endif /* EGL_MESA_screen_surface */
/**
* Parse the list of surface attributes and return the proper error code.
*/
static EGLint
_eglParseSurfaceAttribList(_EGLSurface *surf, const EGLint *attrib_list)
{
_EGLDisplay *dpy = surf->Resource.Display;
EGLint type = surf->Type;
EGLint texture_type = EGL_PBUFFER_BIT;
EGLint i, err = EGL_SUCCESS;
if (!attrib_list)
return EGL_SUCCESS;
#ifdef EGL_MESA_screen_surface
if (type == EGL_SCREEN_BIT_MESA)
return _eglParseScreenSurfaceAttribList(surf, attrib_list);
#endif
if (dpy->Extensions.NOK_texture_from_pixmap)
texture_type |= EGL_PIXMAP_BIT;
for (i = 0; attrib_list[i] != EGL_NONE; i++) {
EGLint attr = attrib_list[i++];
EGLint val = attrib_list[i];
switch (attr) {
/* common attributes */
case EGL_VG_COLORSPACE:
switch (val) {
case EGL_VG_COLORSPACE_sRGB:
case EGL_VG_COLORSPACE_LINEAR:
break;
default:
err = EGL_BAD_ATTRIBUTE;
break;
}
if (err != EGL_SUCCESS)
break;
surf->VGColorspace = val;
break;
case EGL_VG_ALPHA_FORMAT:
switch (val) {
case EGL_VG_ALPHA_FORMAT_NONPRE:
case EGL_VG_ALPHA_FORMAT_PRE:
break;
default:
err = EGL_BAD_ATTRIBUTE;
break;
}
if (err != EGL_SUCCESS)
break;
surf->VGAlphaFormat = val;
break;
/* window surface attributes */
case EGL_RENDER_BUFFER:
if (type != EGL_WINDOW_BIT) {
err = EGL_BAD_ATTRIBUTE;
break;
}
if (val != EGL_BACK_BUFFER && val != EGL_SINGLE_BUFFER) {
err = EGL_BAD_ATTRIBUTE;
break;
}
surf->RenderBuffer = val;
break;
case EGL_POST_SUB_BUFFER_SUPPORTED_NV:
if (!dpy->Extensions.NV_post_sub_buffer ||
type != EGL_WINDOW_BIT) {
err = EGL_BAD_ATTRIBUTE;
break;
}
if (val != EGL_TRUE && val != EGL_FALSE) {
err = EGL_BAD_PARAMETER;
break;
}
surf->PostSubBufferSupportedNV = val;
break;
/* pbuffer surface attributes */
case EGL_WIDTH:
if (type != EGL_PBUFFER_BIT) {
err = EGL_BAD_ATTRIBUTE;
break;
}
if (val < 0) {
err = EGL_BAD_PARAMETER;
break;
}
surf->Width = val;
break;
case EGL_HEIGHT:
if (type != EGL_PBUFFER_BIT) {
err = EGL_BAD_ATTRIBUTE;
break;
}
if (val < 0) {
err = EGL_BAD_PARAMETER;
break;
}
surf->Height = val;
break;
case EGL_LARGEST_PBUFFER:
if (type != EGL_PBUFFER_BIT) {
err = EGL_BAD_ATTRIBUTE;
break;
}
surf->LargestPbuffer = !!val;
break;
/* for eglBindTexImage */
case EGL_TEXTURE_FORMAT:
if (!(type & texture_type)) {
err = EGL_BAD_ATTRIBUTE;
break;
}
switch (val) {
case EGL_TEXTURE_RGB:
case EGL_TEXTURE_RGBA:
case EGL_NO_TEXTURE:
break;
default:
err = EGL_BAD_ATTRIBUTE;
break;
}
if (err != EGL_SUCCESS)
break;
surf->TextureFormat = val;
break;
case EGL_TEXTURE_TARGET:
if (!(type & texture_type)) {
err = EGL_BAD_ATTRIBUTE;
break;
}
switch (val) {
case EGL_TEXTURE_2D:
case EGL_NO_TEXTURE:
break;
default:
err = EGL_BAD_ATTRIBUTE;
break;
}
if (err != EGL_SUCCESS)
break;
surf->TextureTarget = val;
break;
case EGL_MIPMAP_TEXTURE:
if (!(type & texture_type)) {
err = EGL_BAD_ATTRIBUTE;
break;
}
surf->MipmapTexture = !!val;
break;
/* no pixmap surface specific attributes */
default:
err = EGL_BAD_ATTRIBUTE;
break;
}
if (err != EGL_SUCCESS) {
_eglLog(_EGL_WARNING, "bad surface attribute 0x%04x", attr);
break;
}
}
return err;
}
/**
* Do error check on parameters and initialize the given _EGLSurface object.
* \return EGL_TRUE if no errors, EGL_FALSE otherwise.
*/
EGLBoolean
_eglInitSurface(_EGLSurface *surf, _EGLDisplay *dpy, EGLint type,
_EGLConfig *conf, const EGLint *attrib_list)
{
const char *func;
EGLint renderBuffer = EGL_BACK_BUFFER;
EGLint swapBehavior = EGL_BUFFER_PRESERVED;
EGLint err;
printf("%s\n",__FUNCTION__);
switch (type) {
case EGL_WINDOW_BIT:
func = "eglCreateWindowSurface";
swapBehavior = EGL_BUFFER_DESTROYED;
break;
case EGL_PIXMAP_BIT:
func = "eglCreatePixmapSurface";
renderBuffer = EGL_SINGLE_BUFFER;
break;
case EGL_PBUFFER_BIT:
func = "eglCreatePBufferSurface";
break;
#ifdef EGL_MESA_screen_surface
case EGL_SCREEN_BIT_MESA:
func = "eglCreateScreenSurface";
renderBuffer = EGL_SINGLE_BUFFER; /* XXX correct? */
break;
#endif
default:
_eglLog(_EGL_WARNING, "Bad type in _eglInitSurface");
return EGL_FALSE;
}
if ((conf->SurfaceType & type) == 0) {
/* The config can't be used to create a surface of this type */
_eglError(EGL_BAD_CONFIG, func);
return EGL_FALSE;
}
_eglInitResource(&surf->Resource, sizeof(*surf), dpy);
surf->Type = type;
surf->Config = conf;
surf->Width = 0;
surf->Height = 0;
surf->TextureFormat = EGL_NO_TEXTURE;
surf->TextureTarget = EGL_NO_TEXTURE;
surf->MipmapTexture = EGL_FALSE;
surf->LargestPbuffer = EGL_FALSE;
surf->RenderBuffer = renderBuffer;
surf->VGAlphaFormat = EGL_VG_ALPHA_FORMAT_NONPRE;
surf->VGColorspace = EGL_VG_COLORSPACE_sRGB;
surf->MipmapLevel = 0;
surf->MultisampleResolve = EGL_MULTISAMPLE_RESOLVE_DEFAULT;
surf->SwapBehavior = swapBehavior;
surf->HorizontalResolution = EGL_UNKNOWN;
surf->VerticalResolution = EGL_UNKNOWN;
surf->AspectRatio = EGL_UNKNOWN;
surf->PostSubBufferSupportedNV = EGL_FALSE;
/* the default swap interval is 1 */
_eglClampSwapInterval(surf, 1);
err = _eglParseSurfaceAttribList(surf, attrib_list);
if (err != EGL_SUCCESS)
return _eglError(err, func);
return EGL_TRUE;
}
EGLBoolean
_eglQuerySurface(_EGLDriver *drv, _EGLDisplay *dpy, _EGLSurface *surface,
EGLint attribute, EGLint *value)
{
switch (attribute) {
case EGL_WIDTH:
*value = surface->Width;
break;
case EGL_HEIGHT:
*value = surface->Height;
break;
case EGL_CONFIG_ID:
*value = surface->Config->ConfigID;
break;
case EGL_LARGEST_PBUFFER:
*value = surface->LargestPbuffer;
break;
case EGL_TEXTURE_FORMAT:
/* texture attributes: only for pbuffers, no error otherwise */
if (surface->Type == EGL_PBUFFER_BIT)
*value = surface->TextureFormat;
break;
case EGL_TEXTURE_TARGET:
if (surface->Type == EGL_PBUFFER_BIT)
*value = surface->TextureTarget;
break;
case EGL_MIPMAP_TEXTURE:
if (surface->Type == EGL_PBUFFER_BIT)
*value = surface->MipmapTexture;
break;
case EGL_MIPMAP_LEVEL:
if (surface->Type == EGL_PBUFFER_BIT)
*value = surface->MipmapLevel;
break;
case EGL_SWAP_BEHAVIOR:
*value = surface->SwapBehavior;
break;
case EGL_RENDER_BUFFER:
*value = surface->RenderBuffer;
break;
case EGL_PIXEL_ASPECT_RATIO:
*value = surface->AspectRatio;
break;
case EGL_HORIZONTAL_RESOLUTION:
*value = surface->HorizontalResolution;
break;
case EGL_VERTICAL_RESOLUTION:
*value = surface->VerticalResolution;
break;
case EGL_MULTISAMPLE_RESOLVE:
*value = surface->MultisampleResolve;
break;
case EGL_VG_ALPHA_FORMAT:
*value = surface->VGAlphaFormat;
break;
case EGL_VG_COLORSPACE:
*value = surface->VGColorspace;
break;
case EGL_POST_SUB_BUFFER_SUPPORTED_NV:
*value = surface->PostSubBufferSupportedNV;
break;
case EGL_BUFFER_AGE_EXT:
if (!dpy->Extensions.EXT_buffer_age) {
_eglError(EGL_BAD_ATTRIBUTE, "eglQuerySurface");
return EGL_FALSE;
}
*value = drv->API.QueryBufferAge(drv, dpy, surface);
break;
default:
_eglError(EGL_BAD_ATTRIBUTE, "eglQuerySurface");
return EGL_FALSE;
}
return EGL_TRUE;
}
/**
* Default fallback routine - drivers might override this.
*/
EGLBoolean
_eglSurfaceAttrib(_EGLDriver *drv, _EGLDisplay *dpy, _EGLSurface *surface,
EGLint attribute, EGLint value)
{
EGLint confval;
EGLint err = EGL_SUCCESS;
EGLint all_es_bits = EGL_OPENGL_ES_BIT |
EGL_OPENGL_ES2_BIT |
EGL_OPENGL_ES3_BIT_KHR;
switch (attribute) {
case EGL_MIPMAP_LEVEL:
confval = surface->Config->RenderableType;
if (!(confval & all_es_bits)) {
err = EGL_BAD_PARAMETER;
break;
}
surface->MipmapLevel = value;
break;
case EGL_MULTISAMPLE_RESOLVE:
switch (value) {
case EGL_MULTISAMPLE_RESOLVE_DEFAULT:
break;
case EGL_MULTISAMPLE_RESOLVE_BOX:
confval = surface->Config->SurfaceType;
if (!(confval & EGL_MULTISAMPLE_RESOLVE_BOX_BIT))
err = EGL_BAD_MATCH;
break;
default:
err = EGL_BAD_ATTRIBUTE;
break;
}
if (err != EGL_SUCCESS)
break;
surface->MultisampleResolve = value;
break;
case EGL_SWAP_BEHAVIOR:
switch (value) {
case EGL_BUFFER_DESTROYED:
break;
case EGL_BUFFER_PRESERVED:
confval = surface->Config->SurfaceType;
if (!(confval & EGL_SWAP_BEHAVIOR_PRESERVED_BIT))
err = EGL_BAD_MATCH;
break;
default:
err = EGL_BAD_ATTRIBUTE;
break;
}
if (err != EGL_SUCCESS)
break;
surface->SwapBehavior = value;
break;
default:
err = EGL_BAD_ATTRIBUTE;
break;
}
if (err != EGL_SUCCESS)
return _eglError(err, "eglSurfaceAttrib");
return EGL_TRUE;
}
EGLBoolean
_eglBindTexImage(_EGLDriver *drv, _EGLDisplay *dpy, _EGLSurface *surface,
EGLint buffer)
{
EGLint texture_type = EGL_PBUFFER_BIT;
/* Just do basic error checking and return success/fail.
* Drivers must implement the real stuff.
*/
if (dpy->Extensions.NOK_texture_from_pixmap)
texture_type |= EGL_PIXMAP_BIT;
if (!(surface->Type & texture_type)) {
_eglError(EGL_BAD_SURFACE, "eglBindTexImage");
return EGL_FALSE;
}
if (surface->TextureFormat == EGL_NO_TEXTURE) {
_eglError(EGL_BAD_MATCH, "eglBindTexImage");
return EGL_FALSE;
}
if (surface->TextureTarget == EGL_NO_TEXTURE) {
_eglError(EGL_BAD_MATCH, "eglBindTexImage");
return EGL_FALSE;
}
if (buffer != EGL_BACK_BUFFER) {
_eglError(EGL_BAD_PARAMETER, "eglBindTexImage");
return EGL_FALSE;
}
surface->BoundToTexture = EGL_TRUE;
return EGL_TRUE;
}
EGLBoolean
_eglSwapInterval(_EGLDriver *drv, _EGLDisplay *dpy, _EGLSurface *surf,
EGLint interval)
{
_eglClampSwapInterval(surf, interval);
return EGL_TRUE;
}

View File

@ -1,175 +0,0 @@
/**************************************************************************
*
* Copyright 2008 Tungsten Graphics, Inc., Cedar Park, Texas.
* Copyright 2009-2010 Chia-I Wu <olvaffe@gmail.com>
* Copyright 2010 LunarG, 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, sub license, 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 (including the
* next paragraph) 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.
*
**************************************************************************/
#ifndef EGLSURFACE_INCLUDED
#define EGLSURFACE_INCLUDED
#include "egltypedefs.h"
#include "egldisplay.h"
/**
* "Base" class for device driver surfaces.
*/
struct _egl_surface
{
/* A surface is a display resource */
_EGLResource Resource;
/* The context that is currently bound to the surface */
_EGLContext *CurrentContext;
_EGLConfig *Config;
EGLint Type; /* one of EGL_WINDOW_BIT, EGL_PIXMAP_BIT or EGL_PBUFFER_BIT */
/* attributes set by attribute list */
EGLint Width, Height;
EGLenum TextureFormat;
EGLenum TextureTarget;
EGLBoolean MipmapTexture;
EGLBoolean LargestPbuffer;
EGLenum RenderBuffer;
EGLenum VGAlphaFormat;
EGLenum VGColorspace;
/* attributes set by eglSurfaceAttrib */
EGLint MipmapLevel;
EGLenum MultisampleResolve;
EGLenum SwapBehavior;
EGLint HorizontalResolution, VerticalResolution;
EGLint AspectRatio;
EGLint SwapInterval;
/* True if the surface is bound to an OpenGL ES texture */
EGLBoolean BoundToTexture;
EGLBoolean PostSubBufferSupportedNV;
};
PUBLIC EGLBoolean
_eglInitSurface(_EGLSurface *surf, _EGLDisplay *dpy, EGLint type,
_EGLConfig *config, const EGLint *attrib_list);
extern EGLBoolean
_eglQuerySurface(_EGLDriver *drv, _EGLDisplay *dpy, _EGLSurface *surf, EGLint attribute, EGLint *value);
extern EGLBoolean
_eglSurfaceAttrib(_EGLDriver *drv, _EGLDisplay *dpy, _EGLSurface *surf, EGLint attribute, EGLint value);
PUBLIC extern EGLBoolean
_eglBindTexImage(_EGLDriver *drv, _EGLDisplay *dpy, _EGLSurface *surf, EGLint buffer);
extern EGLBoolean
_eglSwapInterval(_EGLDriver *drv, _EGLDisplay *dpy, _EGLSurface *surf, EGLint interval);
/**
* Increment reference count for the surface.
*/
static INLINE _EGLSurface *
_eglGetSurface(_EGLSurface *surf)
{
if (surf)
_eglGetResource(&surf->Resource);
return surf;
}
/**
* Decrement reference count for the surface.
*/
static INLINE EGLBoolean
_eglPutSurface(_EGLSurface *surf)
{
return (surf) ? _eglPutResource(&surf->Resource) : EGL_FALSE;
}
/**
* Link a surface to its display and return the handle of the link.
* The handle can be passed to client directly.
*/
static INLINE EGLSurface
_eglLinkSurface(_EGLSurface *surf)
{
printf("%s surface: %p\n", __FUNCTION__, surf);
_eglLinkResource(&surf->Resource, _EGL_RESOURCE_SURFACE);
return (EGLSurface) surf;
}
/**
* Unlink a linked surface from its display.
* Accessing an unlinked surface should generate EGL_BAD_SURFACE error.
*/
static INLINE void
_eglUnlinkSurface(_EGLSurface *surf)
{
_eglUnlinkResource(&surf->Resource, _EGL_RESOURCE_SURFACE);
}
/**
* Lookup a handle to find the linked surface.
* Return NULL if the handle has no corresponding linked surface.
*/
static INLINE _EGLSurface *
_eglLookupSurface(EGLSurface surface, _EGLDisplay *dpy)
{
_EGLSurface *surf = (_EGLSurface *) surface;
if (!dpy || !_eglCheckResource((void *) surf, _EGL_RESOURCE_SURFACE, dpy))
surf = NULL;
return surf;
}
/**
* Return the handle of a linked surface, or EGL_NO_SURFACE.
*/
static INLINE EGLSurface
_eglGetSurfaceHandle(_EGLSurface *surf)
{
_EGLResource *res = (_EGLResource *) surf;
return (res && _eglIsResourceLinked(res)) ?
(EGLSurface) surf : EGL_NO_SURFACE;
}
#endif /* EGLSURFACE_INCLUDED */

View File

@ -1,673 +0,0 @@
/*
* Copyright © 2011 Intel Corporation
*
* 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 (including the next
* paragraph) 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:
* Benjamin Franzke <benjaminfranzke@googlemail.com>
*/
#include <stdio.h>
#include <stdlib.h>
#include <stddef.h>
#include <stdint.h>
#include <string.h>
#include <limits.h>
#include <sys/types.h>
//#include <sys/mman.h>
#include <unistd.h>
//#include <dlfcn.h>
#include <xf86drm.h>
#include <GL/gl.h> /* dri_interface needs GL types */
#include <GL/internal/dri_interface.h>
#include "gbm_driint.h"
#include "gbmint.h"
/* For importing wl_buffer */
#if HAVE_WAYLAND_PLATFORM
#include "../../../egl/wayland/wayland-drm/wayland-drm.h"
#endif
void *load_library(const char *name);
void *get_proc_address(void *lib, char *proc_name);
static __DRIimage *
dri_lookup_egl_image(__DRIscreen *screen, void *image, void *data)
{
struct gbm_dri_device *dri = data;
if (dri->lookup_image == NULL)
return NULL;
return dri->lookup_image(screen, image, dri->lookup_user_data);
}
static __DRIbuffer *
dri_get_buffers(__DRIdrawable * driDrawable,
int *width, int *height,
unsigned int *attachments, int count,
int *out_count, void *data)
{
struct gbm_dri_surface *surf = data;
struct gbm_dri_device *dri = gbm_dri_device(surf->base.gbm);
if (dri->get_buffers == NULL)
return NULL;
return dri->get_buffers(driDrawable, width, height, attachments,
count, out_count, surf->dri_private);
}
static void
dri_flush_front_buffer(__DRIdrawable * driDrawable, void *data)
{
struct gbm_dri_surface *surf = data;
struct gbm_dri_device *dri = gbm_dri_device(surf->base.gbm);
if (dri->flush_front_buffer != NULL)
dri->flush_front_buffer(driDrawable, surf->dri_private);
}
static __DRIbuffer *
dri_get_buffers_with_format(__DRIdrawable * driDrawable,
int *width, int *height,
unsigned int *attachments, int count,
int *out_count, void *data)
{
struct gbm_dri_surface *surf = data;
struct gbm_dri_device *dri = gbm_dri_device(surf->base.gbm);
if (dri->get_buffers_with_format == NULL)
return NULL;
return
dri->get_buffers_with_format(driDrawable, width, height, attachments,
count, out_count, surf->dri_private);
}
static const __DRIuseInvalidateExtension use_invalidate = {
{ __DRI_USE_INVALIDATE, 1 }
};
static const __DRIimageLookupExtension image_lookup_extension = {
{ __DRI_IMAGE_LOOKUP, 1 },
dri_lookup_egl_image
};
const __DRIdri2LoaderExtension dri2_loader_extension = {
{ __DRI_DRI2_LOADER, 3 },
dri_get_buffers,
dri_flush_front_buffer,
dri_get_buffers_with_format,
};
struct dri_extension_match {
const char *name;
int version;
int offset;
};
static struct dri_extension_match dri_core_extensions[] = {
{ __DRI2_FLUSH, 1, offsetof(struct gbm_dri_device, flush) },
{ __DRI_IMAGE, 1, offsetof(struct gbm_dri_device, image) },
{ NULL, 0, 0 }
};
static struct dri_extension_match gbm_dri_device_extensions[] = {
{ __DRI_CORE, 1, offsetof(struct gbm_dri_device, core) },
{ __DRI_DRI2, 1, offsetof(struct gbm_dri_device, dri2) },
{ NULL, 0, 0 }
};
static int
dri_bind_extensions(struct gbm_dri_device *dri,
struct dri_extension_match *matches,
const __DRIextension **extensions)
{
int i, j, ret = 0;
void *field;
for (i = 0; extensions[i]; i++) {
for (j = 0; matches[j].name; j++) {
if (strcmp(extensions[i]->name, matches[j].name) == 0 &&
extensions[i]->version >= matches[j].version) {
field = ((char *) dri + matches[j].offset);
*(const __DRIextension **) field = extensions[i];
}
}
}
for (j = 0; matches[j].name; j++) {
field = ((char *) dri + matches[j].offset);
if (*(const __DRIextension **) field == NULL) {
ret = -1;
}
}
return ret;
}
static int
dri_load_driver(struct gbm_dri_device *dri)
{
const __DRIextension **extensions;
// char path[PATH_MAX], *search_paths, *p, *next, *end;
char *search_paths;
search_paths = NULL;
#if 0
if (geteuid() == getuid()) {
/* don't allow setuid apps to use GBM_DRIVERS_PATH */
search_paths = getenv("GBM_DRIVERS_PATH");
}
if (search_paths == NULL)
search_paths = DEFAULT_DRIVER_DIR;
dri->driver = NULL;
end = search_paths + strlen(search_paths);
for (p = search_paths; p < end && dri->driver == NULL; p = next + 1) {
int len;
next = strchr(p, ':');
if (next == NULL)
next = end;
len = next - p;
#if GLX_USE_TLS
snprintf(path, sizeof path,
"%.*s/tls/%s_dri.so", len, p, dri->base.driver_name);
dri->driver = dlopen(path, RTLD_NOW | RTLD_GLOBAL);
#endif
if (dri->driver == NULL) {
snprintf(path, sizeof path,
"%.*s/%s_dri.so", len, p, dri->base.driver_name);
dri->driver = dlopen(path, RTLD_NOW | RTLD_GLOBAL);
if (dri->driver == NULL)
fprintf(stderr, "failed to open %s: %s\n", path, dlerror());
}
}
#endif
dri->driver = load_library("libGL.dll");
if (dri->driver == NULL) {
fprintf(stderr, "gbm: failed to open any driver (search paths %s)",
search_paths);
return -1;
}
extensions = get_proc_address(dri->driver, __DRI_DRIVER_EXTENSIONS);
if (extensions == NULL) {
fprintf(stderr, "gbm: driver exports no extensions\n");
// dlclose(dri->driver);
return -1;
}
if (dri_bind_extensions(dri, gbm_dri_device_extensions, extensions) < 0) {
// dlclose(dri->driver);
fprintf(stderr, "failed to bind extensions\n");
return -1;
}
return 0;
}
static int
dri_screen_create(struct gbm_dri_device *dri)
{
const __DRIextension **extensions;
int ret = 0;
dri->base.driver_name = strdup("drm"); //dri_fd_get_driver_name(dri->base.base.fd);
if (dri->base.driver_name == NULL)
return -1;
ret = dri_load_driver(dri);
if (ret) {
fprintf(stderr, "failed to load driver: %s\n", dri->base.driver_name);
return ret;
};
dri->extensions[0] = &image_lookup_extension.base;
dri->extensions[1] = &use_invalidate.base;
dri->extensions[2] = &dri2_loader_extension.base;
dri->extensions[3] = NULL;
if (dri->dri2 == NULL)
return -1;
dri->screen = dri->dri2->createNewScreen(0, dri->base.base.fd,
dri->extensions,
&dri->driver_configs, dri);
if (dri->screen == NULL)
return -1;
extensions = dri->core->getExtensions(dri->screen);
if (dri_bind_extensions(dri, dri_core_extensions, extensions) < 0) {
ret = -1;
goto free_screen;
}
dri->lookup_image = NULL;
dri->lookup_user_data = NULL;
return 0;
free_screen:
dri->core->destroyScreen(dri->screen);
return ret;
}
static int
gbm_dri_is_format_supported(struct gbm_device *gbm,
uint32_t format,
uint32_t usage)
{
switch (format) {
case GBM_BO_FORMAT_XRGB8888:
case GBM_FORMAT_XRGB8888:
break;
case GBM_BO_FORMAT_ARGB8888:
case GBM_FORMAT_ARGB8888:
if (usage & GBM_BO_USE_SCANOUT)
return 0;
break;
default:
return 0;
}
if (usage & GBM_BO_USE_CURSOR_64X64 &&
usage & GBM_BO_USE_RENDERING)
return 0;
return 1;
}
static int
gbm_dri_bo_write(struct gbm_bo *_bo, const void *buf, size_t count)
{
struct gbm_dri_bo *bo = gbm_dri_bo(_bo);
if (bo->image != NULL)
return -1;
memcpy(bo->map, buf, count);
return 0;
}
static void
gbm_dri_bo_destroy(struct gbm_bo *_bo)
{
struct gbm_dri_device *dri = gbm_dri_device(_bo->gbm);
struct gbm_dri_bo *bo = gbm_dri_bo(_bo);
// struct drm_mode_destroy_dumb arg;
if (bo->image != NULL) {
dri->image->destroyImage(bo->image);
} else {
// munmap(bo->map, bo->size);
// memset(&arg, 0, sizeof(arg));
// arg.handle = bo->handle;
// drmIoctl(dri->base.base.fd, DRM_IOCTL_MODE_DESTROY_DUMB, &arg);
}
free(bo);
}
static uint32_t
gbm_dri_to_gbm_format(uint32_t dri_format)
{
uint32_t ret = 0;
switch (dri_format) {
case __DRI_IMAGE_FORMAT_RGB565:
ret = GBM_FORMAT_RGB565;
break;
case __DRI_IMAGE_FORMAT_XRGB8888:
ret = GBM_FORMAT_XRGB8888;
break;
case __DRI_IMAGE_FORMAT_ARGB8888:
ret = GBM_FORMAT_ARGB8888;
break;
case __DRI_IMAGE_FORMAT_ABGR8888:
ret = GBM_FORMAT_ABGR8888;
break;
default:
ret = 0;
break;
}
return ret;
}
static struct gbm_bo *
gbm_dri_bo_import(struct gbm_device *gbm,
uint32_t type, void *buffer, uint32_t usage)
{
struct gbm_dri_device *dri = gbm_dri_device(gbm);
struct gbm_dri_bo *bo;
__DRIimage *image;
unsigned dri_use = 0;
int gbm_format;
/* Required for query image WIDTH & HEIGHT */
if (dri->image->base.version < 4)
return NULL;
switch (type) {
#if HAVE_WAYLAND_PLATFORM
case GBM_BO_IMPORT_WL_BUFFER:
{
struct wl_drm_buffer *wb = (struct wl_drm_buffer *) buffer;
if (!wayland_buffer_is_drm(buffer))
return NULL;
image = wb->driver_buffer;
switch (wb->format) {
case WL_DRM_FORMAT_XRGB8888:
gbm_format = GBM_FORMAT_XRGB8888;
break;
case WL_DRM_FORMAT_ARGB8888:
gbm_format = GBM_FORMAT_ARGB8888;
break;
case WL_DRM_FORMAT_YUYV:
gbm_format = GBM_FORMAT_YUYV;
break;
default:
return NULL;
}
break;
}
#endif
case GBM_BO_IMPORT_EGL_IMAGE:
{
int dri_format;
if (dri->lookup_image == NULL)
return NULL;
image = dri->lookup_image(dri->screen, buffer, dri->lookup_user_data);
dri->image->queryImage(image, __DRI_IMAGE_ATTRIB_FORMAT, &dri_format);
gbm_format = gbm_dri_to_gbm_format(dri_format);
if (gbm_format == 0)
return NULL;
break;
}
default:
return NULL;
}
bo = calloc(1, sizeof *bo);
if (bo == NULL)
return NULL;
bo->image = dri->image->dupImage(image, NULL);
if (usage & GBM_BO_USE_SCANOUT)
dri_use |= __DRI_IMAGE_USE_SCANOUT;
if (usage & GBM_BO_USE_CURSOR_64X64)
dri_use |= __DRI_IMAGE_USE_CURSOR;
if (dri->image->base.version >= 2 &&
!dri->image->validateUsage(bo->image, dri_use)) {
free(bo);
return NULL;
}
bo->base.base.gbm = gbm;
bo->base.base.format = gbm_format;
dri->image->queryImage(bo->image, __DRI_IMAGE_ATTRIB_WIDTH,
(int*)&bo->base.base.width);
dri->image->queryImage(bo->image, __DRI_IMAGE_ATTRIB_HEIGHT,
(int*)&bo->base.base.height);
dri->image->queryImage(bo->image, __DRI_IMAGE_ATTRIB_STRIDE,
(int*)&bo->base.base.stride);
dri->image->queryImage(bo->image, __DRI_IMAGE_ATTRIB_HANDLE,
&bo->base.base.handle.s32);
return &bo->base.base;
}
#if 0
static struct gbm_bo *
create_dumb(struct gbm_device *gbm,
uint32_t width, uint32_t height,
uint32_t format, uint32_t usage)
{
struct gbm_dri_device *dri = gbm_dri_device(gbm);
struct drm_mode_create_dumb create_arg;
struct drm_mode_map_dumb map_arg;
struct gbm_dri_bo *bo;
struct drm_mode_destroy_dumb destroy_arg;
int ret;
if (!(usage & GBM_BO_USE_CURSOR_64X64))
return NULL;
if (format != GBM_FORMAT_ARGB8888)
return NULL;
bo = calloc(1, sizeof *bo);
if (bo == NULL)
return NULL;
create_arg.bpp = 32;
create_arg.width = width;
create_arg.height = height;
ret = drmIoctl(dri->base.base.fd, DRM_IOCTL_MODE_CREATE_DUMB, &create_arg);
if (ret)
goto free_bo;
bo->base.base.gbm = gbm;
bo->base.base.width = width;
bo->base.base.height = height;
bo->base.base.stride = create_arg.pitch;
bo->base.base.format = format;
bo->base.base.handle.u32 = create_arg.handle;
bo->handle = create_arg.handle;
bo->size = create_arg.size;
memset(&map_arg, 0, sizeof(map_arg));
map_arg.handle = bo->handle;
ret = drmIoctl(dri->base.base.fd, DRM_IOCTL_MODE_MAP_DUMB, &map_arg);
if (ret)
goto destroy_dumb;
bo->map = mmap(0, bo->size, PROT_WRITE,
MAP_SHARED, dri->base.base.fd, map_arg.offset);
if (bo->map == MAP_FAILED)
goto destroy_dumb;
return &bo->base.base;
destroy_dumb:
memset(&destroy_arg, 0, sizeof destroy_arg);
destroy_arg.handle = create_arg.handle;
drmIoctl(dri->base.base.fd, DRM_IOCTL_MODE_DESTROY_DUMB, &destroy_arg);
free_bo:
free(bo);
return NULL;
}
#endif
static struct gbm_bo *
gbm_dri_bo_create(struct gbm_device *gbm,
uint32_t width, uint32_t height,
uint32_t format, uint32_t usage)
{
struct gbm_dri_device *dri = gbm_dri_device(gbm);
struct gbm_dri_bo *bo;
int dri_format;
unsigned dri_use = 0;
// if (usage & GBM_BO_USE_WRITE)
// return create_dumb(gbm, width, height, format, usage);
bo = calloc(1, sizeof *bo);
if (bo == NULL)
return NULL;
bo->base.base.gbm = gbm;
bo->base.base.width = width;
bo->base.base.height = height;
bo->base.base.format = format;
switch (format) {
case GBM_FORMAT_RGB565:
dri_format =__DRI_IMAGE_FORMAT_RGB565;
break;
case GBM_FORMAT_XRGB8888:
case GBM_BO_FORMAT_XRGB8888:
dri_format = __DRI_IMAGE_FORMAT_XRGB8888;
break;
case GBM_FORMAT_ARGB8888:
case GBM_BO_FORMAT_ARGB8888:
dri_format = __DRI_IMAGE_FORMAT_ARGB8888;
break;
case GBM_FORMAT_ABGR8888:
dri_format = __DRI_IMAGE_FORMAT_ABGR8888;
break;
default:
return NULL;
}
if (usage & GBM_BO_USE_SCANOUT)
dri_use |= __DRI_IMAGE_USE_SCANOUT;
if (usage & GBM_BO_USE_CURSOR_64X64)
dri_use |= __DRI_IMAGE_USE_CURSOR;
/* Gallium drivers requires shared in order to get the handle/stride */
dri_use |= __DRI_IMAGE_USE_SHARE;
bo->image =
dri->image->createImage(dri->screen,
width, height,
dri_format, dri_use,
bo);
if (bo->image == NULL)
return NULL;
dri->image->queryImage(bo->image, __DRI_IMAGE_ATTRIB_HANDLE,
&bo->base.base.handle.s32);
dri->image->queryImage(bo->image, __DRI_IMAGE_ATTRIB_STRIDE,
(int *) &bo->base.base.stride);
printf("gbm_dri_bo_create bo: %p handle %d"
" width: %d height: %d pitch: %d format %d\n",bo, bo->base.base.handle.s32,
bo->base.base.width, bo->base.base.height,
(int)bo->base.base.stride,bo->base.base.format);
return &bo->base.base;
}
static struct gbm_surface *
gbm_dri_surface_create(struct gbm_device *gbm,
uint32_t width, uint32_t height,
uint32_t format, uint32_t flags)
{
struct gbm_dri_surface *surf;
surf = calloc(1, sizeof *surf);
if (surf == NULL)
return NULL;
surf->base.gbm = gbm;
surf->base.width = width;
surf->base.height = height;
surf->base.format = format;
surf->base.flags = flags;
return &surf->base;
}
static void
gbm_dri_surface_destroy(struct gbm_surface *_surf)
{
struct gbm_dri_surface *surf = gbm_dri_surface(_surf);
free(surf);
}
static void
dri_destroy(struct gbm_device *gbm)
{
struct gbm_dri_device *dri = gbm_dri_device(gbm);
dri->core->destroyScreen(dri->screen);
free(dri->driver_configs);
// dlclose(dri->driver);
free(dri->base.driver_name);
free(dri);
}
static struct gbm_device *
dri_device_create(int fd)
{
struct gbm_dri_device *dri;
int ret;
dri = calloc(1, sizeof *dri);
dri->base.base.fd = fd;
dri->base.base.bo_create = gbm_dri_bo_create;
dri->base.base.bo_import = gbm_dri_bo_import;
dri->base.base.is_format_supported = gbm_dri_is_format_supported;
dri->base.base.bo_write = gbm_dri_bo_write;
dri->base.base.bo_destroy = gbm_dri_bo_destroy;
dri->base.base.destroy = dri_destroy;
dri->base.base.surface_create = gbm_dri_surface_create;
dri->base.base.surface_destroy = gbm_dri_surface_destroy;
dri->base.type = GBM_DRM_DRIVER_TYPE_DRI;
dri->base.base.name = "drm";
ret = dri_screen_create(dri);
if (ret)
goto err_dri;
return &dri->base.base;
err_dri:
free(dri);
return NULL;
}
struct gbm_backend gbm_dri_backend = {
.backend_name = "dri",
.create_device = dri_device_create,
};

View File

@ -1,472 +0,0 @@
/*
* Copyright © 2011 Intel Corporation
*
* 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 (including the next
* paragraph) 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:
* Benjamin Franzke <benjaminfranzke@googlemail.com>
*/
#define _BSD_SOURCE
#include <stddef.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stdint.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
#include "gbm.h"
#include "gbmint.h"
#include "common.h"
#include "backend.h"
#define ARRAY_SIZE(a) (sizeof(a)/sizeof((a)[0]))
struct gbm_device *devices[16];
static int device_num = 0;
/** Returns the file description for the gbm device
*
* \return The fd that the struct gbm_device was created with
*/
GBM_EXPORT int
gbm_device_get_fd(struct gbm_device *gbm)
{
return gbm->fd;
}
/* FIXME: maybe superfluous, use udev subclass from the fd? */
/** Get the backend name for the given gbm device
*
* \return The backend name string - this belongs to the device and must not
* be freed
*/
GBM_EXPORT const char *
gbm_device_get_backend_name(struct gbm_device *gbm)
{
return gbm->name;
}
/** Test if a format is supported for a given set of usage flags.
*
* \param gbm The created buffer manager
* \param format The format to test
* \param usage A bitmask of the usages to test the format against
* \return 1 if the format is supported otherwise 0
*
* \sa enum gbm_bo_flags for the list of flags that the format can be
* tested against
*
* \sa enum gbm_bo_format for the list of formats
*/
int
gbm_device_is_format_supported(struct gbm_device *gbm,
uint32_t format, uint32_t usage)
{
return gbm->is_format_supported(gbm, format, usage);
}
/** Destroy the gbm device and free all resources associated with it.
*
* \param gbm The device created using gbm_create_device()
*/
GBM_EXPORT void
gbm_device_destroy(struct gbm_device *gbm)
{
gbm->refcount--;
if (gbm->refcount == 0)
gbm->destroy(gbm);
}
#if 0
GBM_EXPORT struct gbm_device *
_gbm_mesa_get_device(int fd)
{
struct gbm_device *gbm = NULL;
struct stat buf;
dev_t dev;
int i;
for (i = 0; i < device_num; ++i) {
dev = devices[i]->stat.st_rdev;
if (major(dev) == major(buf.st_rdev) &&
minor(dev) == minor(buf.st_rdev)) {
gbm = devices[i];
gbm->refcount++;
break;
}
}
return gbm;
}
#endif
/** Create a gbm device for allocating buffers
*
* The file descriptor passed in is used by the backend to communicate with
* platform for allocating the memory. For allocations using DRI this would be
* the file descriptor returned when opening a device such as \c
* /dev/dri/card0
*
* \param fd The file descriptor for an backend specific device
* \return The newly created struct gbm_device. The resources associated with
* the device should be freed with gbm_device_destroy() when it is no longer
* needed. If the creation of the device failed NULL will be returned.
*/
GBM_EXPORT struct gbm_device *
gbm_create_device(int fd)
{
struct gbm_device *gbm = NULL;
struct stat buf;
if (fd == 0) {
fprintf(stderr, "gbm_create_device: invalid fd: %d\n", fd);
return NULL;
}
if (device_num == 0)
memset(devices, 0, sizeof devices);
gbm = _gbm_create_device(fd);
if (gbm == NULL)
return NULL;
gbm->dummy = gbm_create_device;
gbm->stat = buf;
gbm->refcount = 1;
if (device_num < ARRAY_SIZE(devices)-1)
devices[device_num++] = gbm;
return gbm;
}
/** Get the width of the buffer object
*
* \param bo The buffer object
* \return The width of the allocated buffer object
*
*/
GBM_EXPORT unsigned int
gbm_bo_get_width(struct gbm_bo *bo)
{
return bo->width;
}
/** Get the height of the buffer object
*
* \param bo The buffer object
* \return The height of the allocated buffer object
*/
GBM_EXPORT unsigned int
gbm_bo_get_height(struct gbm_bo *bo)
{
return bo->height;
}
/** Get the stride of the buffer object
*
* This is calculated by the backend when it does the allocation in
* gbm_bo_create()
*
* \param bo The buffer object
* \return The stride of the allocated buffer object in bytes
*/
GBM_EXPORT uint32_t
gbm_bo_get_stride(struct gbm_bo *bo)
{
return bo->stride;
}
/** Get the format of the buffer object
*
* The format of the pixels in the buffer.
*
* \param bo The buffer object
* \return The format of buffer object, on of the GBM_FORMAT_* codes
*/
GBM_EXPORT uint32_t
gbm_bo_get_format(struct gbm_bo *bo)
{
return bo->format;
}
/** Get the handle of the buffer object
*
* This is stored in the platform generic union gbm_bo_handle type. However
* the format of this handle is platform specific.
*
* \param bo The buffer object
* \return Returns the handle of the allocated buffer object
*/
GBM_EXPORT union gbm_bo_handle
gbm_bo_get_handle(struct gbm_bo *bo)
{
return bo->handle;
}
/** Write data into the buffer object
*
* If the buffer object was created with the GBM_BO_USE_WRITE flag,
* this function can used to write data into the buffer object. The
* data is copied directly into the object and it's the responsiblity
* of the caller to make sure the data represents valid pixel data,
* according to the width, height, stride and format of the buffer object.
*
* \param bo The buffer object
* \param buf The data to write
* \param count The number of bytes to write
* \return Returns -1 on error, 0 otherwise
*/
GBM_EXPORT int
gbm_bo_write(struct gbm_bo *bo, const void *buf, size_t count)
{
return bo->gbm->bo_write(bo, buf, count);
}
/** Get the gbm device used to create the buffer object
*
* \param bo The buffer object
* \return Returns the gbm device with which the buffer object was created
*/
GBM_EXPORT struct gbm_device *
gbm_bo_get_device(struct gbm_bo *bo)
{
return bo->gbm;
}
/** Set the user data associated with a buffer object
*
* \param bo The buffer object
* \param data The data to associate to the buffer object
* \param destroy_user_data A callback (which may be %NULL) that will be
* called prior to the buffer destruction
*/
GBM_EXPORT void
gbm_bo_set_user_data(struct gbm_bo *bo, void *data,
void (*destroy_user_data)(struct gbm_bo *, void *))
{
bo->user_data = data;
bo->destroy_user_data = destroy_user_data;
}
/** Get the user data associated with a buffer object
*
* \param bo The buffer object
* \return Returns the user data associated with the buffer object or %NULL
* if no data was associated with it
*
* \sa gbm_bo_set_user_data()
*/
GBM_EXPORT void *
gbm_bo_get_user_data(struct gbm_bo *bo)
{
return bo->user_data;
}
/**
* Destroys the given buffer object and frees all resources associated with
* it.
*
* \param bo The buffer object
*/
GBM_EXPORT void
gbm_bo_destroy(struct gbm_bo *bo)
{
if (bo->destroy_user_data)
bo->destroy_user_data(bo, bo->user_data);
bo->gbm->bo_destroy(bo);
}
/**
* Allocate a buffer object for the given dimensions
*
* \param gbm The gbm device returned from gbm_create_device()
* \param width The width for the buffer
* \param height The height for the buffer
* \param format The format to use for the buffer
* \param usage The union of the usage flags for this buffer
*
* \return A newly allocated buffer that should be freed with gbm_bo_destroy()
* when no longer needed. If an error occurs during allocation %NULL will be
* returned.
*
* \sa enum gbm_bo_format for the list of formats
* \sa enum gbm_bo_flags for the list of usage flags
*/
GBM_EXPORT struct gbm_bo *
gbm_bo_create(struct gbm_device *gbm,
uint32_t width, uint32_t height,
uint32_t format, uint32_t usage)
{
printf("gbm_bo_create w: %d h: %d format %d usage %x\n",
width, height, format, usage);
if (width == 0 || height == 0)
return NULL;
if (usage & GBM_BO_USE_CURSOR_64X64 &&
(width != 64 || height != 64))
return NULL;
return gbm->bo_create(gbm, width, height, format, usage);
}
/**
* Create a gbm buffer object from an foreign object
*
* This function imports a foreign object and creates a new gbm bo for it.
* This enabled using the foreign object with a display API such as KMS.
* Currently two types of foreign objects are supported, indicated by the type
* argument:
*
* GBM_BO_IMPORT_WL_BUFFER
* GBM_BO_IMPORT_EGL_IMAGE
*
* The the gbm bo shares the underlying pixels but its life-time is
* independent of the foreign object.
*
* \param gbm The gbm device returned from gbm_create_device()
* \param gbm The type of object we're importing
* \param gbm Pointer to the external object
* \param usage The union of the usage flags for this buffer
*
* \return A newly allocated buffer object that should be freed with
* gbm_bo_destroy() when no longer needed.
*
* \sa enum gbm_bo_flags for the list of usage flags
*/
GBM_EXPORT struct gbm_bo *
gbm_bo_import(struct gbm_device *gbm,
uint32_t type, void *buffer, uint32_t usage)
{
return gbm->bo_import(gbm, type, buffer, usage);
}
/**
* Allocate a surface object
*
* \param gbm The gbm device returned from gbm_create_device()
* \param width The width for the surface
* \param height The height for the surface
* \param format The format to use for the surface
*
* \return A newly allocated surface that should be freed with
* gbm_surface_destroy() when no longer needed. If an error occurs
* during allocation %NULL will be returned.
*
* \sa enum gbm_bo_format for the list of formats
*/
GBM_EXPORT struct gbm_surface *
gbm_surface_create(struct gbm_device *gbm,
uint32_t width, uint32_t height,
uint32_t format, uint32_t flags)
{
return gbm->surface_create(gbm, width, height, format, flags);
}
/**
* Destroys the given surface and frees all resources associated with
* it.
*
* All buffers locked with gbm_surface_lock_front_buffer() should be
* released prior to calling this function.
*
* \param surf The surface
*/
GBM_EXPORT void
gbm_surface_destroy(struct gbm_surface *surf)
{
surf->gbm->surface_destroy(surf);
}
/**
* Lock the surface's current front buffer
*
* Lock rendering to the surface's current front buffer until it is
* released with gbm_surface_release_buffer().
*
* This function must be called exactly once after calling
* eglSwapBuffers. Calling it before any eglSwapBuffer has happened
* on the surface or two or more times after eglSwapBuffers is an
* error. A new bo representing the new front buffer is returned. On
* multiple invocations, all the returned bos must be released in
* order to release the actual surface buffer.
*
* \param surf The surface
*
* \return A buffer object that should be released with
* gbm_surface_release_buffer() when no longer needed. The implementation
* is free to reuse buffers released with gbm_surface_release_buffer() so
* this bo should not be destroyed using gbm_bo_destroy(). If an error
* occurs this function returns %NULL.
*/
GBM_EXPORT struct gbm_bo *
gbm_surface_lock_front_buffer(struct gbm_surface *surf)
{
return surf->gbm->surface_lock_front_buffer(surf);
}
/**
* Release a locked buffer obtained with gbm_surface_lock_front_buffer()
*
* Returns the underlying buffer to the gbm surface. Releasing a bo
* will typically make gbm_surface_has_free_buffer() return 1 and thus
* allow rendering the next frame, but not always. The implementation
* may choose to destroy the bo immediately or reuse it, in which case
* the user data associated with it is unchanged.
*
* \param surf The surface
* \param bo The buffer object
*/
GBM_EXPORT void
gbm_surface_release_buffer(struct gbm_surface *surf, struct gbm_bo *bo)
{
surf->gbm->surface_release_buffer(surf, bo);
}
/**
* Return whether or not a surface has free (non-locked) buffers
*
* Before starting a new frame, the surface must have a buffer
* available for rendering. Initially, a gbm surface will have a free
* buffer, but after one of more buffers have been locked (\sa
* gbm_surface_lock_front_buffer()), the application must check for a
* free buffer before rendering.
*
* If a surface doesn't have a free buffer, the application must
* return a buffer to the surface using gbm_surface_release_buffer()
* and after that, the application can query for free buffers again.
*
* \param surf The surface
* \return 1 if the surface has free buffers, 0 otherwise
*/
GBM_EXPORT int
gbm_surface_has_free_buffers(struct gbm_surface *surf)
{
return surf->gbm->surface_has_free_buffers(surf);
}

File diff suppressed because it is too large Load Diff

View File

@ -1,632 +0,0 @@
/*
* (C) Copyright IBM Corporation 2002, 2004
* 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
* on the rights to use, copy, modify, merge, publish, distribute, sub
* license, 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 (including the next
* paragraph) 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 NON-INFRINGEMENT. IN NO EVENT SHALL
* THE AUTHORS AND/OR THEIR SUPPLIERS 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.
*/
/**
* \file dri_util.c
* DRI utility functions.
*
* This module acts as glue between GLX and the actual hardware driver. A DRI
* driver doesn't really \e have to use any of this - it's optional. But, some
* useful stuff is done here that otherwise would have to be duplicated in most
* drivers.
*
* Basically, these utility functions take care of some of the dirty details of
* screen initialization, context creation, context binding, DRM setup, etc.
*
* These functions are compiled into each DRI driver so libGL.so knows nothing
* about them.
*/
#include <xf86drm.h>
#include "dri_util.h"
#include "utils.h"
#include "xmlpool.h"
#include "../glsl/glsl_parser_extras.h"
PUBLIC const char __dri2ConfigOptions[] =
DRI_CONF_BEGIN
DRI_CONF_SECTION_PERFORMANCE
DRI_CONF_VBLANK_MODE(DRI_CONF_VBLANK_DEF_INTERVAL_1)
DRI_CONF_SECTION_END
DRI_CONF_END;
static const uint __dri2NConfigOptions = 1;
/*****************************************************************/
/** \name Screen handling functions */
/*****************************************************************/
/*@{*/
static void
setupLoaderExtensions(__DRIscreen *psp,
const __DRIextension **extensions)
{
int i;
for (i = 0; extensions[i]; i++) {
if (strcmp(extensions[i]->name, __DRI_DRI2_LOADER) == 0)
psp->dri2.loader = (__DRIdri2LoaderExtension *) extensions[i];
if (strcmp(extensions[i]->name, __DRI_IMAGE_LOOKUP) == 0)
psp->dri2.image = (__DRIimageLookupExtension *) extensions[i];
if (strcmp(extensions[i]->name, __DRI_USE_INVALIDATE) == 0)
psp->dri2.useInvalidate = (__DRIuseInvalidateExtension *) extensions[i];
}
}
static __DRIscreen *
dri2CreateNewScreen(int scrn, int fd,
const __DRIextension **extensions,
const __DRIconfig ***driver_configs, void *data)
{
static const __DRIextension *emptyExtensionList[] = { NULL };
__DRIscreen *psp;
drmVersionPtr version;
psp = calloc(1, sizeof(*psp));
if (!psp)
return NULL;
setupLoaderExtensions(psp, extensions);
version = drmGetVersion(fd);
if (version) {
psp->drm_version.major = version->version_major;
psp->drm_version.minor = version->version_minor;
psp->drm_version.patch = version->version_patchlevel;
drmFreeVersion(version);
}
psp->loaderPrivate = data;
psp->extensions = emptyExtensionList;
psp->fd = fd;
psp->myNum = scrn;
psp->api_mask = (1 << __DRI_API_OPENGL);
*driver_configs = driDriverAPI.InitScreen(psp);
if (*driver_configs == NULL) {
free(psp);
return NULL;
}
driParseOptionInfo(&psp->optionInfo, __dri2ConfigOptions, __dri2NConfigOptions);
driParseConfigFiles(&psp->optionCache, &psp->optionInfo, psp->myNum, "dri2");
return psp;
}
/**
* Destroy the per-screen private information.
*
* \internal
* This function calls __DriverAPIRec::DestroyScreen on \p screenPrivate, calls
* drmClose(), and finally frees \p screenPrivate.
*/
static void driDestroyScreen(__DRIscreen *psp)
{
if (psp) {
/* No interaction with the X-server is possible at this point. This
* routine is called after XCloseDisplay, so there is no protocol
* stream open to the X-server anymore.
*/
_mesa_destroy_shader_compiler();
driDriverAPI.DestroyScreen(psp);
driDestroyOptionCache(&psp->optionCache);
driDestroyOptionInfo(&psp->optionInfo);
free(psp);
}
}
static const __DRIextension **driGetExtensions(__DRIscreen *psp)
{
return psp->extensions;
}
/*@}*/
/*****************************************************************/
/** \name Context handling functions */
/*****************************************************************/
/*@{*/
static __DRIcontext *
dri2CreateContextAttribs(__DRIscreen *screen, int api,
const __DRIconfig *config,
__DRIcontext *shared,
unsigned num_attribs,
const uint32_t *attribs,
unsigned *error,
void *data)
{
__DRIcontext *context;
const struct gl_config *modes = (config != NULL) ? &config->modes : NULL;
void *shareCtx = (shared != NULL) ? shared->driverPrivate : NULL;
gl_api mesa_api;
unsigned major_version = 1;
unsigned minor_version = 0;
uint32_t flags = 0;
assert((num_attribs == 0) || (attribs != NULL));
if (!(screen->api_mask & (1 << api))) {
*error = __DRI_CTX_ERROR_BAD_API;
return NULL;
}
switch (api) {
case __DRI_API_OPENGL:
mesa_api = API_OPENGL_COMPAT;
break;
case __DRI_API_GLES:
mesa_api = API_OPENGLES;
break;
case __DRI_API_GLES2:
case __DRI_API_GLES3:
mesa_api = API_OPENGLES2;
break;
case __DRI_API_OPENGL_CORE:
mesa_api = API_OPENGL_CORE;
break;
default:
*error = __DRI_CTX_ERROR_BAD_API;
return NULL;
}
for (unsigned i = 0; i < num_attribs; i++) {
switch (attribs[i * 2]) {
case __DRI_CTX_ATTRIB_MAJOR_VERSION:
major_version = attribs[i * 2 + 1];
break;
case __DRI_CTX_ATTRIB_MINOR_VERSION:
minor_version = attribs[i * 2 + 1];
break;
case __DRI_CTX_ATTRIB_FLAGS:
flags = attribs[i * 2 + 1];
break;
default:
/* We can't create a context that satisfies the requirements of an
* attribute that we don't understand. Return failure.
*/
assert(!"Should not get here.");
*error = __DRI_CTX_ERROR_UNKNOWN_ATTRIBUTE;
return NULL;
}
}
/* Mesa does not support the GL_ARB_compatibilty extension or the
* compatibility profile. This means that we treat a API_OPENGL_COMPAT 3.1 as
* API_OPENGL_CORE and reject API_OPENGL_COMPAT 3.2+.
*/
if (mesa_api == API_OPENGL_COMPAT && major_version == 3 && minor_version == 1)
mesa_api = API_OPENGL_CORE;
if (mesa_api == API_OPENGL_COMPAT
&& ((major_version > 3)
|| (major_version == 3 && minor_version >= 2))) {
*error = __DRI_CTX_ERROR_BAD_API;
return NULL;
}
/* The EGL_KHR_create_context spec says:
*
* "Flags are only defined for OpenGL context creation, and specifying
* a flags value other than zero for other types of contexts,
* including OpenGL ES contexts, will generate an error."
*
* The GLX_EXT_create_context_es2_profile specification doesn't say
* anything specific about this case. However, none of the known flags
* have any meaning in an ES context, so this seems safe.
*/
if (mesa_api != API_OPENGL_COMPAT
&& mesa_api != API_OPENGL_CORE
&& flags != 0) {
*error = __DRI_CTX_ERROR_BAD_FLAG;
return NULL;
}
/* There are no forward-compatible contexts before OpenGL 3.0. The
* GLX_ARB_create_context spec says:
*
* "Forward-compatible contexts are defined only for OpenGL versions
* 3.0 and later."
*
* Forward-looking contexts are supported by silently converting the
* requested API to API_OPENGL_CORE.
*
* In Mesa, a debug context is the same as a regular context.
*/
if ((flags & __DRI_CTX_FLAG_FORWARD_COMPATIBLE) != 0) {
mesa_api = API_OPENGL_CORE;
}
if ((flags & ~(__DRI_CTX_FLAG_DEBUG | __DRI_CTX_FLAG_FORWARD_COMPATIBLE))
!= 0) {
*error = __DRI_CTX_ERROR_UNKNOWN_FLAG;
return NULL;
}
context = calloc(1, sizeof *context);
if (!context) {
*error = __DRI_CTX_ERROR_NO_MEMORY;
return NULL;
}
context->loaderPrivate = data;
context->driScreenPriv = screen;
context->driDrawablePriv = NULL;
context->driReadablePriv = NULL;
if (!driDriverAPI.CreateContext(mesa_api, modes, context,
major_version, minor_version,
flags, error, shareCtx) ) {
free(context);
return NULL;
}
*error = __DRI_CTX_ERROR_SUCCESS;
return context;
}
static __DRIcontext *
dri2CreateNewContextForAPI(__DRIscreen *screen, int api,
const __DRIconfig *config,
__DRIcontext *shared, void *data)
{
unsigned error;
return dri2CreateContextAttribs(screen, api, config, shared, 0, NULL,
&error, data);
}
static __DRIcontext *
dri2CreateNewContext(__DRIscreen *screen, const __DRIconfig *config,
__DRIcontext *shared, void *data)
{
return dri2CreateNewContextForAPI(screen, __DRI_API_OPENGL,
config, shared, data);
}
/**
* Destroy the per-context private information.
*
* \internal
* This function calls __DriverAPIRec::DestroyContext on \p contextPrivate, calls
* drmDestroyContext(), and finally frees \p contextPrivate.
*/
static void
driDestroyContext(__DRIcontext *pcp)
{
if (pcp) {
driDriverAPI.DestroyContext(pcp);
free(pcp);
}
}
static int
driCopyContext(__DRIcontext *dest, __DRIcontext *src, unsigned long mask)
{
(void) dest;
(void) src;
(void) mask;
return GL_FALSE;
}
/*@}*/
/*****************************************************************/
/** \name Context (un)binding functions */
/*****************************************************************/
/*@{*/
static void dri_get_drawable(__DRIdrawable *pdp);
static void dri_put_drawable(__DRIdrawable *pdp);
/**
* This function takes both a read buffer and a draw buffer. This is needed
* for \c glXMakeCurrentReadSGI or GLX 1.3's \c glXMakeContextCurrent
* function.
*/
static int driBindContext(__DRIcontext *pcp,
__DRIdrawable *pdp,
__DRIdrawable *prp)
{
/*
** Assume error checking is done properly in glXMakeCurrent before
** calling driUnbindContext.
*/
if (!pcp)
return GL_FALSE;
/* Bind the drawable to the context */
pcp->driDrawablePriv = pdp;
pcp->driReadablePriv = prp;
if (pdp) {
pdp->driContextPriv = pcp;
dri_get_drawable(pdp);
}
if (prp && pdp != prp) {
dri_get_drawable(prp);
}
return driDriverAPI.MakeCurrent(pcp, pdp, prp);
}
/**
* Unbind context.
*
* \param scrn the screen.
* \param gc context.
*
* \return \c GL_TRUE on success, or \c GL_FALSE on failure.
*
* \internal
* This function calls __DriverAPIRec::UnbindContext, and then decrements
* __DRIdrawableRec::refcount which must be non-zero for a successful
* return.
*
* While casting the opaque private pointers associated with the parameters
* into their respective real types it also assures they are not \c NULL.
*/
static int driUnbindContext(__DRIcontext *pcp)
{
__DRIdrawable *pdp;
__DRIdrawable *prp;
/*
** Assume error checking is done properly in glXMakeCurrent before
** calling driUnbindContext.
*/
if (pcp == NULL)
return GL_FALSE;
pdp = pcp->driDrawablePriv;
prp = pcp->driReadablePriv;
/* already unbound */
if (!pdp && !prp)
return GL_TRUE;
driDriverAPI.UnbindContext(pcp);
assert(pdp);
if (pdp->refcount == 0) {
/* ERROR!!! */
return GL_FALSE;
}
dri_put_drawable(pdp);
if (prp != pdp) {
if (prp->refcount == 0) {
/* ERROR!!! */
return GL_FALSE;
}
dri_put_drawable(prp);
}
/* XXX this is disabled so that if we call SwapBuffers on an unbound
* window we can determine the last context bound to the window and
* use that context's lock. (BrianP, 2-Dec-2000)
*/
pcp->driDrawablePriv = NULL;
pcp->driReadablePriv = NULL;
return GL_TRUE;
}
/*@}*/
static void dri_get_drawable(__DRIdrawable *pdp)
{
pdp->refcount++;
}
static void dri_put_drawable(__DRIdrawable *pdp)
{
if (pdp) {
pdp->refcount--;
if (pdp->refcount)
return;
driDriverAPI.DestroyBuffer(pdp);
free(pdp);
}
}
static __DRIdrawable *
dri2CreateNewDrawable(__DRIscreen *screen,
const __DRIconfig *config,
void *data)
{
__DRIdrawable *pdraw;
printf("%s: screen %p config %p, data %p\n",
__FUNCTION__, screen, config, data);
pdraw = malloc(sizeof *pdraw);
if (!pdraw)
return NULL;
pdraw->loaderPrivate = data;
pdraw->driScreenPriv = screen;
pdraw->driContextPriv = NULL;
pdraw->refcount = 0;
pdraw->lastStamp = 0;
pdraw->w = 0;
pdraw->h = 0;
dri_get_drawable(pdraw);
if (!driDriverAPI.CreateBuffer(screen, pdraw, &config->modes, GL_FALSE)) {
free(pdraw);
return NULL;
}
pdraw->dri2.stamp = pdraw->lastStamp + 1;
return pdraw;
}
static void
driDestroyDrawable(__DRIdrawable *pdp)
{
dri_put_drawable(pdp);
}
static __DRIbuffer *
dri2AllocateBuffer(__DRIscreen *screen,
unsigned int attachment, unsigned int format,
int width, int height)
{
return driDriverAPI.AllocateBuffer(screen, attachment, format,
width, height);
}
static void
dri2ReleaseBuffer(__DRIscreen *screen, __DRIbuffer *buffer)
{
driDriverAPI.ReleaseBuffer(screen, buffer);
}
static int
dri2ConfigQueryb(__DRIscreen *screen, const char *var, GLboolean *val)
{
if (!driCheckOption(&screen->optionCache, var, DRI_BOOL))
return -1;
*val = driQueryOptionb(&screen->optionCache, var);
return 0;
}
static int
dri2ConfigQueryi(__DRIscreen *screen, const char *var, GLint *val)
{
if (!driCheckOption(&screen->optionCache, var, DRI_INT) &&
!driCheckOption(&screen->optionCache, var, DRI_ENUM))
return -1;
*val = driQueryOptioni(&screen->optionCache, var);
return 0;
}
static int
dri2ConfigQueryf(__DRIscreen *screen, const char *var, GLfloat *val)
{
if (!driCheckOption(&screen->optionCache, var, DRI_FLOAT))
return -1;
*val = driQueryOptionf(&screen->optionCache, var);
return 0;
}
static unsigned int
dri2GetAPIMask(__DRIscreen *screen)
{
return screen->api_mask;
}
/** Core interface */
const __DRIcoreExtension driCoreExtension = {
.base = { __DRI_CORE, __DRI_CORE_VERSION },
.createNewScreen = NULL,
.destroyScreen = driDestroyScreen,
.getExtensions = driGetExtensions,
.getConfigAttrib = driGetConfigAttrib,
.indexConfigAttrib = driIndexConfigAttrib,
.createNewDrawable = NULL,
.destroyDrawable = driDestroyDrawable,
.swapBuffers = NULL,
.createNewContext = NULL,
.copyContext = driCopyContext,
.destroyContext = driDestroyContext,
.bindContext = driBindContext,
.unbindContext = driUnbindContext
};
/** DRI2 interface */
const __DRIdri2Extension driDRI2Extension = {
.base = { __DRI_DRI2, 3 },
.createNewScreen = dri2CreateNewScreen,
.createNewDrawable = dri2CreateNewDrawable,
.createNewContext = dri2CreateNewContext,
.getAPIMask = dri2GetAPIMask,
.createNewContextForAPI = dri2CreateNewContextForAPI,
.allocateBuffer = dri2AllocateBuffer,
.releaseBuffer = dri2ReleaseBuffer,
.createContextAttribs = dri2CreateContextAttribs
};
const __DRI2configQueryExtension dri2ConfigQueryExtension = {
.base = { __DRI2_CONFIG_QUERY, __DRI2_CONFIG_QUERY_VERSION },
.configQueryb = dri2ConfigQueryb,
.configQueryi = dri2ConfigQueryi,
.configQueryf = dri2ConfigQueryf,
};
void
dri2InvalidateDrawable(__DRIdrawable *drawable)
{
drawable->dri2.stamp++;
}
/**
* Check that the gl_framebuffer associated with dPriv is the right size.
* Resize the gl_framebuffer if needed.
* It's expected that the dPriv->driverPrivate member points to a
* gl_framebuffer object.
*/
void
driUpdateFramebufferSize(struct gl_context *ctx, const __DRIdrawable *dPriv)
{
struct gl_framebuffer *fb = (struct gl_framebuffer *) dPriv->driverPrivate;
if (fb && (dPriv->w != fb->Width || dPriv->h != fb->Height)) {
ctx->Driver.ResizeBuffers(ctx, fb, dPriv->w, dPriv->h);
/* if the driver needs the hw lock for ResizeBuffers, the drawable
might have changed again by now */
assert(fb->Width == dPriv->w);
assert(fb->Height == dPriv->h);
}
}

View File

@ -1,920 +0,0 @@
/**************************************************************************
*
* Copyright 2003 Tungsten Graphics, Inc., Cedar Park, Texas.
* 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, sub license, 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 (including the
* next paragraph) 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 NON-INFRINGEMENT.
* IN NO EVENT SHALL TUNGSTEN GRAPHICS AND/OR ITS SUPPLIERS 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 "main/glheader.h"
#include "main/context.h"
#include "main/extensions.h"
#include "main/fbobject.h"
#include "main/framebuffer.h"
#include "main/imports.h"
#include "main/renderbuffer.h"
#include "swrast/swrast.h"
#include "swrast_setup/swrast_setup.h"
#include "tnl/tnl.h"
#include "drivers/common/driverfuncs.h"
#include "drivers/common/meta.h"
#include "intel_chipset.h"
#include "intel_buffers.h"
#include "intel_tex.h"
#include "intel_batchbuffer.h"
#include "intel_pixel.h"
#include "intel_regions.h"
#include "intel_buffer_objects.h"
#include "intel_fbo.h"
#include "intel_bufmgr.h"
#include "intel_screen.h"
#include "intel_mipmap_tree.h"
#include "utils.h"
#include "../glsl/ralloc.h"
#ifndef INTEL_DEBUG
int INTEL_DEBUG = (0);
#endif
static const GLubyte *
intelGetString(struct gl_context * ctx, GLenum name)
{
const struct brw_context *const brw = brw_context(ctx);
const char *chipset;
static char buffer[128];
switch (name) {
case GL_VENDOR:
return (GLubyte *) "Intel Open Source Technology Center";
break;
case GL_RENDERER:
switch (brw->intelScreen->deviceID) {
#undef CHIPSET
#define CHIPSET(id, symbol, str) case id: chipset = str; break;
#include "pci_ids/i965_pci_ids.h"
default:
chipset = "Unknown Intel Chipset";
break;
}
(void) driGetRendererString(buffer, chipset, 0);
return (GLubyte *) buffer;
default:
return NULL;
}
}
void
intel_resolve_for_dri2_flush(struct brw_context *brw,
__DRIdrawable *drawable)
{
if (brw->gen < 6) {
/* MSAA and fast color clear are not supported, so don't waste time
* checking whether a resolve is needed.
*/
return;
}
struct gl_framebuffer *fb = drawable->driverPrivate;
struct intel_renderbuffer *rb;
/* Usually, only the back buffer will need to be downsampled. However,
* the front buffer will also need it if the user has rendered into it.
*/
static const gl_buffer_index buffers[2] = {
BUFFER_BACK_LEFT,
BUFFER_FRONT_LEFT,
};
for (int i = 0; i < 2; ++i) {
rb = intel_get_renderbuffer(fb, buffers[i]);
if (rb == NULL || rb->mt == NULL)
continue;
if (rb->mt->num_samples <= 1)
intel_miptree_resolve_color(brw, rb->mt);
else
intel_miptree_downsample(brw, rb->mt);
}
}
static void
intel_flush_front(struct gl_context *ctx)
{
struct brw_context *brw = brw_context(ctx);
__DRIcontext *driContext = brw->driContext;
__DRIdrawable *driDrawable = driContext->driDrawablePriv;
__DRIscreen *const screen = brw->intelScreen->driScrnPriv;
if (brw->front_buffer_dirty && _mesa_is_winsys_fbo(ctx->DrawBuffer)) {
if (screen->dri2.loader->flushFrontBuffer != NULL &&
driDrawable &&
driDrawable->loaderPrivate) {
/* Resolve before flushing FAKE_FRONT_LEFT to FRONT_LEFT.
*
* This potentially resolves both front and back buffer. It
* is unnecessary to resolve the back, but harms nothing except
* performance. And no one cares about front-buffer render
* performance.
*/
intel_resolve_for_dri2_flush(brw, driDrawable);
screen->dri2.loader->flushFrontBuffer(driDrawable,
driDrawable->loaderPrivate);
/* We set the dirty bit in intel_prepare_render() if we're
* front buffer rendering once we get there.
*/
brw->front_buffer_dirty = false;
}
}
}
static unsigned
intel_bits_per_pixel(const struct intel_renderbuffer *rb)
{
return _mesa_get_format_bytes(intel_rb_format(rb)) * 8;
}
static void
intel_query_dri2_buffers(struct brw_context *brw,
__DRIdrawable *drawable,
__DRIbuffer **buffers,
int *count);
static void
intel_process_dri2_buffer(struct brw_context *brw,
__DRIdrawable *drawable,
__DRIbuffer *buffer,
struct intel_renderbuffer *rb,
const char *buffer_name);
void
intel_update_renderbuffers(__DRIcontext *context, __DRIdrawable *drawable)
{
struct gl_framebuffer *fb = drawable->driverPrivate;
struct intel_renderbuffer *rb;
struct brw_context *brw = context->driverPrivate;
__DRIbuffer *buffers = NULL;
int i, count;
const char *region_name;
/* Set this up front, so that in case our buffers get invalidated
* while we're getting new buffers, we don't clobber the stamp and
* thus ignore the invalidate. */
drawable->lastStamp = drawable->dri2.stamp;
if (unlikely(INTEL_DEBUG & DEBUG_DRI))
fprintf(stderr, "enter %s, drawable %p\n", __func__, drawable);
intel_query_dri2_buffers(brw, drawable, &buffers, &count);
if (buffers == NULL)
return;
for (i = 0; i < count; i++) {
switch (buffers[i].attachment) {
case __DRI_BUFFER_FRONT_LEFT:
rb = intel_get_renderbuffer(fb, BUFFER_FRONT_LEFT);
region_name = "dri2 front buffer";
break;
case __DRI_BUFFER_FAKE_FRONT_LEFT:
rb = intel_get_renderbuffer(fb, BUFFER_FRONT_LEFT);
region_name = "dri2 fake front buffer";
break;
case __DRI_BUFFER_BACK_LEFT:
rb = intel_get_renderbuffer(fb, BUFFER_BACK_LEFT);
region_name = "dri2 back buffer";
break;
case __DRI_BUFFER_DEPTH:
case __DRI_BUFFER_HIZ:
case __DRI_BUFFER_DEPTH_STENCIL:
case __DRI_BUFFER_STENCIL:
case __DRI_BUFFER_ACCUM:
default:
fprintf(stderr,
"unhandled buffer attach event, attachment type %d\n",
buffers[i].attachment);
return;
}
intel_process_dri2_buffer(brw, drawable, &buffers[i], rb, region_name);
}
driUpdateFramebufferSize(&brw->ctx, drawable);
}
/**
* intel_prepare_render should be called anywhere that curent read/drawbuffer
* state is required.
*/
void
intel_prepare_render(struct brw_context *brw)
{
__DRIcontext *driContext = brw->driContext;
__DRIdrawable *drawable;
drawable = driContext->driDrawablePriv;
if (drawable && drawable->dri2.stamp != driContext->dri2.draw_stamp) {
if (drawable->lastStamp != drawable->dri2.stamp)
intel_update_renderbuffers(driContext, drawable);
driContext->dri2.draw_stamp = drawable->dri2.stamp;
}
drawable = driContext->driReadablePriv;
if (drawable && drawable->dri2.stamp != driContext->dri2.read_stamp) {
if (drawable->lastStamp != drawable->dri2.stamp)
intel_update_renderbuffers(driContext, drawable);
driContext->dri2.read_stamp = drawable->dri2.stamp;
}
/* If we're currently rendering to the front buffer, the rendering
* that will happen next will probably dirty the front buffer. So
* mark it as dirty here.
*/
if (brw->is_front_buffer_rendering)
brw->front_buffer_dirty = true;
/* Wait for the swapbuffers before the one we just emitted, so we
* don't get too many swaps outstanding for apps that are GPU-heavy
* but not CPU-heavy.
*
* We're using intelDRI2Flush (called from the loader before
* swapbuffer) and glFlush (for front buffer rendering) as the
* indicator that a frame is done and then throttle when we get
* here as we prepare to render the next frame. At this point for
* round trips for swap/copy and getting new buffers are done and
* we'll spend less time waiting on the GPU.
*
* Unfortunately, we don't have a handle to the batch containing
* the swap, and getting our hands on that doesn't seem worth it,
* so we just us the first batch we emitted after the last swap.
*/
if (brw->need_throttle && brw->first_post_swapbuffers_batch) {
if (!brw->disable_throttling)
drm_intel_bo_wait_rendering(brw->first_post_swapbuffers_batch);
drm_intel_bo_unreference(brw->first_post_swapbuffers_batch);
brw->first_post_swapbuffers_batch = NULL;
brw->need_throttle = false;
}
}
static void
intel_viewport(struct gl_context *ctx, GLint x, GLint y, GLsizei w, GLsizei h)
{
struct brw_context *brw = brw_context(ctx);
__DRIcontext *driContext = brw->driContext;
if (brw->saved_viewport)
brw->saved_viewport(ctx, x, y, w, h);
if (_mesa_is_winsys_fbo(ctx->DrawBuffer)) {
dri2InvalidateDrawable(driContext->driDrawablePriv);
dri2InvalidateDrawable(driContext->driReadablePriv);
}
}
static const struct dri_debug_control debug_control[] = {
{ "tex", DEBUG_TEXTURE},
{ "state", DEBUG_STATE},
{ "ioctl", DEBUG_IOCTL},
{ "blit", DEBUG_BLIT},
{ "mip", DEBUG_MIPTREE},
{ "fall", DEBUG_PERF},
{ "perf", DEBUG_PERF},
{ "bat", DEBUG_BATCH},
{ "pix", DEBUG_PIXEL},
{ "buf", DEBUG_BUFMGR},
{ "reg", DEBUG_REGION},
{ "fbo", DEBUG_FBO},
{ "fs", DEBUG_WM },
{ "gs", DEBUG_GS},
{ "sync", DEBUG_SYNC},
{ "prim", DEBUG_PRIMS },
{ "vert", DEBUG_VERTS },
{ "dri", DEBUG_DRI },
{ "sf", DEBUG_SF },
{ "stats", DEBUG_STATS },
{ "wm", DEBUG_WM },
{ "urb", DEBUG_URB },
{ "vs", DEBUG_VS },
{ "clip", DEBUG_CLIP },
{ "aub", DEBUG_AUB },
{ "shader_time", DEBUG_SHADER_TIME },
{ "no16", DEBUG_NO16 },
{ "blorp", DEBUG_BLORP },
{ NULL, 0 }
};
static void
intelInvalidateState(struct gl_context * ctx, GLuint new_state)
{
struct brw_context *brw = brw_context(ctx);
if (ctx->swrast_context)
_swrast_InvalidateState(ctx, new_state);
_vbo_InvalidateState(ctx, new_state);
brw->NewGLState |= new_state;
}
void
_intel_flush(struct gl_context *ctx, const char *file, int line)
{
struct brw_context *brw = brw_context(ctx);
if (brw->batch.used)
_intel_batchbuffer_flush(brw, file, line);
}
static void
intel_glFlush(struct gl_context *ctx)
{
struct brw_context *brw = brw_context(ctx);
intel_flush(ctx);
intel_flush_front(ctx);
if (brw->is_front_buffer_rendering)
brw->need_throttle = true;
}
void
intelFinish(struct gl_context * ctx)
{
struct brw_context *brw = brw_context(ctx);
intel_flush(ctx);
intel_flush_front(ctx);
if (brw->batch.last_bo)
drm_intel_bo_wait_rendering(brw->batch.last_bo);
}
void
intelInitDriverFunctions(struct dd_function_table *functions)
{
_mesa_init_driver_functions(functions);
functions->Flush = intel_glFlush;
functions->Finish = intelFinish;
functions->GetString = intelGetString;
functions->UpdateState = intelInvalidateState;
intelInitTextureFuncs(functions);
intelInitTextureImageFuncs(functions);
intelInitTextureSubImageFuncs(functions);
intelInitTextureCopyImageFuncs(functions);
intelInitClearFuncs(functions);
intelInitBufferFuncs(functions);
intelInitPixelFuncs(functions);
intelInitBufferObjectFuncs(functions);
intel_init_syncobj_functions(functions);
}
static bool
validate_context_version(struct intel_screen *screen,
int mesa_api,
unsigned major_version,
unsigned minor_version,
unsigned *dri_ctx_error)
{
unsigned req_version = 10 * major_version + minor_version;
unsigned max_version = 0;
switch (mesa_api) {
case API_OPENGL_COMPAT:
max_version = screen->max_gl_compat_version;
break;
case API_OPENGL_CORE:
max_version = screen->max_gl_core_version;
break;
case API_OPENGLES:
max_version = screen->max_gl_es1_version;
break;
case API_OPENGLES2:
max_version = screen->max_gl_es2_version;
break;
default:
max_version = 0;
break;
}
if (max_version == 0) {
*dri_ctx_error = __DRI_CTX_ERROR_BAD_API;
return false;
} else if (req_version > max_version) {
*dri_ctx_error = __DRI_CTX_ERROR_BAD_VERSION;
return false;
}
return true;
}
bool
intelInitContext(struct brw_context *brw,
int api,
unsigned major_version,
unsigned minor_version,
const struct gl_config * mesaVis,
__DRIcontext * driContextPriv,
void *sharedContextPrivate,
struct dd_function_table *functions,
unsigned *dri_ctx_error)
{
struct gl_context *ctx = &brw->ctx;
struct gl_context *shareCtx = (struct gl_context *) sharedContextPrivate;
__DRIscreen *sPriv = driContextPriv->driScreenPriv;
struct intel_screen *intelScreen = sPriv->driverPrivate;
int bo_reuse_mode;
struct gl_config visual;
/* we can't do anything without a connection to the device */
if (intelScreen->bufmgr == NULL) {
*dri_ctx_error = __DRI_CTX_ERROR_NO_MEMORY;
return false;
}
if (!validate_context_version(intelScreen,
api, major_version, minor_version,
dri_ctx_error))
return false;
/* Can't rely on invalidate events, fall back to glViewport hack */
if (!driContextPriv->driScreenPriv->dri2.useInvalidate) {
brw->saved_viewport = functions->Viewport;
functions->Viewport = intel_viewport;
}
if (mesaVis == NULL) {
memset(&visual, 0, sizeof visual);
mesaVis = &visual;
}
brw->intelScreen = intelScreen;
if (!_mesa_initialize_context(&brw->ctx, api, mesaVis, shareCtx,
functions)) {
*dri_ctx_error = __DRI_CTX_ERROR_NO_MEMORY;
printf("%s: failed to init mesa context\n", __FUNCTION__);
return false;
}
driContextPriv->driverPrivate = brw;
brw->driContext = driContextPriv;
brw->gen = intelScreen->gen;
const int devID = intelScreen->deviceID;
if (IS_SNB_GT1(devID) || IS_IVB_GT1(devID) || IS_HSW_GT1(devID))
brw->gt = 1;
else if (IS_SNB_GT2(devID) || IS_IVB_GT2(devID) || IS_HSW_GT2(devID))
brw->gt = 2;
else if (IS_HSW_GT3(devID))
brw->gt = 3;
else
brw->gt = 0;
if (IS_HASWELL(devID)) {
brw->is_haswell = true;
} else if (IS_BAYTRAIL(devID)) {
brw->is_baytrail = true;
brw->gt = 1;
} else if (IS_G4X(devID)) {
brw->is_g4x = true;
}
brw->has_separate_stencil = brw->intelScreen->hw_has_separate_stencil;
brw->must_use_separate_stencil = brw->intelScreen->hw_must_use_separate_stencil;
brw->has_hiz = brw->gen >= 6;
brw->has_llc = brw->intelScreen->hw_has_llc;
brw->has_swizzling = brw->intelScreen->hw_has_swizzling;
memset(&ctx->TextureFormatSupported,
0, sizeof(ctx->TextureFormatSupported));
driParseConfigFiles(&brw->optionCache, &intelScreen->optionCache,
sPriv->myNum, "i965");
/* Estimate the size of the mappable aperture into the GTT. There's an
* ioctl to get the whole GTT size, but not one to get the mappable subset.
* It turns out it's basically always 256MB, though some ancient hardware
* was smaller.
*/
uint32_t gtt_size = 256 * 1024 * 1024;
/* We don't want to map two objects such that a memcpy between them would
* just fault one mapping in and then the other over and over forever. So
* we would need to divide the GTT size by 2. Additionally, some GTT is
* taken up by things like the framebuffer and the ringbuffer and such, so
* be more conservative.
*/
brw->max_gtt_map_object_size = gtt_size / 4;
brw->bufmgr = intelScreen->bufmgr;
bo_reuse_mode = driQueryOptioni(&brw->optionCache, "bo_reuse");
switch (bo_reuse_mode) {
case DRI_CONF_BO_REUSE_DISABLED:
break;
case DRI_CONF_BO_REUSE_ALL:
intel_bufmgr_gem_enable_reuse(brw->bufmgr);
break;
}
/* Initialize the software rasterizer and helper modules.
*
* As of GL 3.1 core, the gen4+ driver doesn't need the swrast context for
* software fallbacks (which we have to support on legacy GL to do weird
* glDrawPixels(), glBitmap(), and other functions).
*/
if (api != API_OPENGL_CORE) {
_swrast_CreateContext(ctx);
}
_vbo_CreateContext(ctx);
if (ctx->swrast_context) {
_tnl_CreateContext(ctx);
_swsetup_CreateContext(ctx);
/* Configure swrast to match hardware characteristics: */
_swrast_allow_pixel_fog(ctx, false);
_swrast_allow_vertex_fog(ctx, true);
}
_mesa_meta_init(ctx);
intelInitExtensions(ctx);
INTEL_DEBUG = driParseDebugString(getenv("INTEL_DEBUG"), debug_control);
if (INTEL_DEBUG & DEBUG_BUFMGR)
dri_bufmgr_set_debug(brw->bufmgr, true);
if ((INTEL_DEBUG & DEBUG_SHADER_TIME) && brw->gen < 7) {
fprintf(stderr,
"shader_time debugging requires gen7 (Ivybridge) or better.\n");
INTEL_DEBUG &= ~DEBUG_SHADER_TIME;
}
if (INTEL_DEBUG & DEBUG_PERF)
brw->perf_debug = true;
if (INTEL_DEBUG & DEBUG_AUB)
drm_intel_bufmgr_gem_set_aub_dump(brw->bufmgr, true);
intel_batchbuffer_init(brw);
intel_fbo_init(brw);
if (!driQueryOptionb(&brw->optionCache, "hiz")) {
brw->has_hiz = false;
/* On gen6, you can only do separate stencil with HIZ. */
if (brw->gen == 6)
brw->has_separate_stencil = false;
}
if (driQueryOptionb(&brw->optionCache, "always_flush_batch")) {
fprintf(stderr, "flushing batchbuffer before/after each draw call\n");
brw->always_flush_batch = 1;
}
if (driQueryOptionb(&brw->optionCache, "always_flush_cache")) {
fprintf(stderr, "flushing GPU caches before/after each draw call\n");
brw->always_flush_cache = 1;
}
if (driQueryOptionb(&brw->optionCache, "disable_throttling")) {
fprintf(stderr, "disabling flush throttling\n");
brw->disable_throttling = 1;
}
return true;
}
void
intelDestroyContext(__DRIcontext * driContextPriv)
{
struct brw_context *brw =
(struct brw_context *) driContextPriv->driverPrivate;
struct gl_context *ctx = &brw->ctx;
assert(brw); /* should never be null */
if (brw) {
/* Dump a final BMP in case the application doesn't call SwapBuffers */
if (INTEL_DEBUG & DEBUG_AUB) {
intel_batchbuffer_flush(brw);
aub_dump_bmp(&brw->ctx);
}
_mesa_meta_free(&brw->ctx);
brw->vtbl.destroy(brw);
if (ctx->swrast_context) {
_swsetup_DestroyContext(&brw->ctx);
_tnl_DestroyContext(&brw->ctx);
}
_vbo_DestroyContext(&brw->ctx);
if (ctx->swrast_context)
_swrast_DestroyContext(&brw->ctx);
intel_batchbuffer_free(brw);
drm_intel_bo_unreference(brw->first_post_swapbuffers_batch);
brw->first_post_swapbuffers_batch = NULL;
driDestroyOptionCache(&brw->optionCache);
/* free the Mesa context */
_mesa_free_context_data(&brw->ctx);
ralloc_free(brw);
driContextPriv->driverPrivate = NULL;
}
}
GLboolean
intelUnbindContext(__DRIcontext * driContextPriv)
{
/* Unset current context and dispath table */
_mesa_make_current(NULL, NULL, NULL);
return true;
}
/**
* Fixes up the context for GLES23 with our default-to-sRGB-capable behavior
* on window system framebuffers.
*
* Desktop GL is fairly reasonable in its handling of sRGB: You can ask if
* your renderbuffer can do sRGB encode, and you can flip a switch that does
* sRGB encode if the renderbuffer can handle it. You can ask specifically
* for a visual where you're guaranteed to be capable, but it turns out that
* everyone just makes all their ARGB8888 visuals capable and doesn't offer
* incapable ones, becuase there's no difference between the two in resources
* used. Applications thus get built that accidentally rely on the default
* visual choice being sRGB, so we make ours sRGB capable. Everything sounds
* great...
*
* But for GLES2/3, they decided that it was silly to not turn on sRGB encode
* for sRGB renderbuffers you made with the GL_EXT_texture_sRGB equivalent.
* So they removed the enable knob and made it "if the renderbuffer is sRGB
* capable, do sRGB encode". Then, for your window system renderbuffers, you
* can ask for sRGB visuals and get sRGB encode, or not ask for sRGB visuals
* and get no sRGB encode (assuming that both kinds of visual are available).
* Thus our choice to support sRGB by default on our visuals for desktop would
* result in broken rendering of GLES apps that aren't expecting sRGB encode.
*
* Unfortunately, renderbuffer setup happens before a context is created. So
* in intel_screen.c we always set up sRGB, and here, if you're a GLES2/3
* context (without an sRGB visual, though we don't have sRGB visuals exposed
* yet), we go turn that back off before anyone finds out.
*/
static void
intel_gles3_srgb_workaround(struct brw_context *brw,
struct gl_framebuffer *fb)
{
struct gl_context *ctx = &brw->ctx;
if (_mesa_is_desktop_gl(ctx) || !fb->Visual.sRGBCapable)
return;
/* Some day when we support the sRGB capable bit on visuals available for
* GLES, we'll need to respect that and not disable things here.
*/
fb->Visual.sRGBCapable = false;
for (int i = 0; i < BUFFER_COUNT; i++) {
if (fb->Attachment[i].Renderbuffer &&
fb->Attachment[i].Renderbuffer->Format == MESA_FORMAT_SARGB8) {
fb->Attachment[i].Renderbuffer->Format = MESA_FORMAT_ARGB8888;
}
}
}
GLboolean
intelMakeCurrent(__DRIcontext * driContextPriv,
__DRIdrawable * driDrawPriv,
__DRIdrawable * driReadPriv)
{
struct brw_context *brw;
GET_CURRENT_CONTEXT(curCtx);
if (driContextPriv)
brw = (struct brw_context *) driContextPriv->driverPrivate;
else
brw = NULL;
/* According to the glXMakeCurrent() man page: "Pending commands to
* the previous context, if any, are flushed before it is released."
* But only flush if we're actually changing contexts.
*/
if (brw_context(curCtx) && brw_context(curCtx) != brw) {
_mesa_flush(curCtx);
}
if (driContextPriv) {
struct gl_context *ctx = &brw->ctx;
struct gl_framebuffer *fb, *readFb;
if (driDrawPriv == NULL && driReadPriv == NULL) {
fb = _mesa_get_incomplete_framebuffer();
readFb = _mesa_get_incomplete_framebuffer();
} else {
fb = driDrawPriv->driverPrivate;
readFb = driReadPriv->driverPrivate;
driContextPriv->dri2.draw_stamp = driDrawPriv->dri2.stamp - 1;
driContextPriv->dri2.read_stamp = driReadPriv->dri2.stamp - 1;
}
/* The sRGB workaround changes the renderbuffer's format. We must change
* the format before the renderbuffer's miptree get's allocated, otherwise
* the formats of the renderbuffer and its miptree will differ.
*/
intel_gles3_srgb_workaround(brw, fb);
intel_gles3_srgb_workaround(brw, readFb);
intel_prepare_render(brw);
_mesa_make_current(ctx, fb, readFb);
}
else {
_mesa_make_current(NULL, NULL, NULL);
}
return true;
}
/**
* \brief Query DRI2 to obtain a DRIdrawable's buffers.
*
* To determine which DRI buffers to request, examine the renderbuffers
* attached to the drawable's framebuffer. Then request the buffers with
* DRI2GetBuffers() or DRI2GetBuffersWithFormat().
*
* This is called from intel_update_renderbuffers().
*
* \param drawable Drawable whose buffers are queried.
* \param buffers [out] List of buffers returned by DRI2 query.
* \param buffer_count [out] Number of buffers returned.
*
* \see intel_update_renderbuffers()
* \see DRI2GetBuffers()
* \see DRI2GetBuffersWithFormat()
*/
static void
intel_query_dri2_buffers(struct brw_context *brw,
__DRIdrawable *drawable,
__DRIbuffer **buffers,
int *buffer_count)
{
__DRIscreen *screen = brw->intelScreen->driScrnPriv;
struct gl_framebuffer *fb = drawable->driverPrivate;
int i = 0;
unsigned attachments[8];
struct intel_renderbuffer *front_rb;
struct intel_renderbuffer *back_rb;
front_rb = intel_get_renderbuffer(fb, BUFFER_FRONT_LEFT);
back_rb = intel_get_renderbuffer(fb, BUFFER_BACK_LEFT);
memset(attachments, 0, sizeof(attachments));
if ((brw->is_front_buffer_rendering ||
brw->is_front_buffer_reading ||
!back_rb) && front_rb) {
/* If a fake front buffer is in use, then querying for
* __DRI_BUFFER_FRONT_LEFT will cause the server to copy the image from
* the real front buffer to the fake front buffer. So before doing the
* query, we need to make sure all the pending drawing has landed in the
* real front buffer.
*/
intel_flush(&brw->ctx);
intel_flush_front(&brw->ctx);
attachments[i++] = __DRI_BUFFER_FRONT_LEFT;
attachments[i++] = intel_bits_per_pixel(front_rb);
} else if (front_rb && brw->front_buffer_dirty) {
/* We have pending front buffer rendering, but we aren't querying for a
* front buffer. If the front buffer we have is a fake front buffer,
* the X server is going to throw it away when it processes the query.
* So before doing the query, make sure all the pending drawing has
* landed in the real front buffer.
*/
intel_flush(&brw->ctx);
intel_flush_front(&brw->ctx);
}
if (back_rb) {
attachments[i++] = __DRI_BUFFER_BACK_LEFT;
attachments[i++] = intel_bits_per_pixel(back_rb);
}
assert(i <= ARRAY_SIZE(attachments));
*buffers = screen->dri2.loader->getBuffersWithFormat(drawable,
&drawable->w,
&drawable->h,
attachments, i / 2,
buffer_count,
drawable->loaderPrivate);
LEAVE();
}
/**
* \brief Assign a DRI buffer's DRM region to a renderbuffer.
*
* This is called from intel_update_renderbuffers().
*
* \par Note:
* DRI buffers whose attachment point is DRI2BufferStencil or
* DRI2BufferDepthStencil are handled as special cases.
*
* \param buffer_name is a human readable name, such as "dri2 front buffer",
* that is passed to intel_region_alloc_for_handle().
*
* \see intel_update_renderbuffers()
* \see intel_region_alloc_for_handle()
*/
static void
intel_process_dri2_buffer(struct brw_context *brw,
__DRIdrawable *drawable,
__DRIbuffer *buffer,
struct intel_renderbuffer *rb,
const char *buffer_name)
{
struct intel_region *region = NULL;
if (!rb)
return;
unsigned num_samples = rb->Base.Base.NumSamples;
/* We try to avoid closing and reopening the same BO name, because the first
* use of a mapping of the buffer involves a bunch of page faulting which is
* moderately expensive.
*/
if (num_samples == 0) {
if (rb->mt &&
rb->mt->region &&
rb->mt->region->name == buffer->name)
return;
} else {
if (rb->mt &&
rb->mt->singlesample_mt &&
rb->mt->singlesample_mt->region &&
rb->mt->singlesample_mt->region->name == buffer->name)
return;
}
if (unlikely(INTEL_DEBUG & DEBUG_DRI)) {
fprintf(stderr,
"attaching buffer %d, at %d, cpp %d, pitch %d\n",
buffer->name, buffer->attachment,
buffer->cpp, buffer->pitch);
}
intel_miptree_release(&rb->mt);
region = intel_region_alloc_for_handle(brw->intelScreen,
buffer->cpp,
drawable->w,
drawable->h,
buffer->pitch,
buffer->name,
buffer_name);
if (!region)
return;
rb->mt = intel_miptree_create_for_dri2_buffer(brw,
buffer->attachment,
intel_rb_format(rb),
num_samples,
region);
intel_region_release(&region);
}

View File

@ -1,899 +0,0 @@
/**************************************************************************
*
* Copyright 2006 Tungsten Graphics, Inc., Cedar Park, Texas.
* 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, sub license, 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 (including the
* next paragraph) 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 NON-INFRINGEMENT.
* IN NO EVENT SHALL TUNGSTEN GRAPHICS AND/OR ITS SUPPLIERS 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 "main/enums.h"
#include "main/imports.h"
#include "main/macros.h"
#include "main/mtypes.h"
#include "main/fbobject.h"
#include "main/framebuffer.h"
#include "main/renderbuffer.h"
#include "main/context.h"
#include "main/teximage.h"
#include "main/image.h"
#include "swrast/swrast.h"
#include "drivers/common/meta.h"
#include "intel_batchbuffer.h"
#include "intel_buffers.h"
#include "intel_blit.h"
#include "intel_fbo.h"
#include "intel_mipmap_tree.h"
#include "intel_regions.h"
#include "intel_tex.h"
#include "brw_context.h"
#define FILE_DEBUG_FLAG DEBUG_FBO
/**
* Create a new framebuffer object.
*/
static struct gl_framebuffer *
intel_new_framebuffer(struct gl_context * ctx, GLuint name)
{
/* Only drawable state in intel_framebuffer at this time, just use Mesa's
* class
*/
return _mesa_new_framebuffer(ctx, name);
}
/** Called by gl_renderbuffer::Delete() */
static void
intel_delete_renderbuffer(struct gl_context *ctx, struct gl_renderbuffer *rb)
{
struct intel_renderbuffer *irb = intel_renderbuffer(rb);
ASSERT(irb);
intel_miptree_release(&irb->mt);
_mesa_delete_renderbuffer(ctx, rb);
}
/**
* \see dd_function_table::MapRenderbuffer
*/
static void
intel_map_renderbuffer(struct gl_context *ctx,
struct gl_renderbuffer *rb,
GLuint x, GLuint y, GLuint w, GLuint h,
GLbitfield mode,
GLubyte **out_map,
GLint *out_stride)
{
struct brw_context *brw = brw_context(ctx);
struct swrast_renderbuffer *srb = (struct swrast_renderbuffer *)rb;
struct intel_renderbuffer *irb = intel_renderbuffer(rb);
void *map;
int stride;
if (srb->Buffer) {
/* this is a malloc'd renderbuffer (accum buffer), not an irb */
GLint bpp = _mesa_get_format_bytes(rb->Format);
GLint rowStride = srb->RowStride;
*out_map = (GLubyte *) srb->Buffer + y * rowStride + x * bpp;
*out_stride = rowStride;
return;
}
intel_prepare_render(brw);
/* For a window-system renderbuffer, we need to flip the mapping we receive
* upside-down. So we need to ask for a rectangle on flipped vertically, and
* we then return a pointer to the bottom of it with a negative stride.
*/
if (rb->Name == 0) {
y = rb->Height - y - h;
}
intel_miptree_map(brw, irb->mt, irb->mt_level, irb->mt_layer,
x, y, w, h, mode, &map, &stride);
if (rb->Name == 0) {
map += (h - 1) * stride;
stride = -stride;
}
DBG("%s: rb %d (%s) mt mapped: (%d, %d) (%dx%d) -> %p/%d\n",
__FUNCTION__, rb->Name, _mesa_get_format_name(rb->Format),
x, y, w, h, map, stride);
*out_map = map;
*out_stride = stride;
}
/**
* \see dd_function_table::UnmapRenderbuffer
*/
static void
intel_unmap_renderbuffer(struct gl_context *ctx,
struct gl_renderbuffer *rb)
{
struct brw_context *brw = brw_context(ctx);
struct swrast_renderbuffer *srb = (struct swrast_renderbuffer *)rb;
struct intel_renderbuffer *irb = intel_renderbuffer(rb);
DBG("%s: rb %d (%s)\n", __FUNCTION__,
rb->Name, _mesa_get_format_name(rb->Format));
if (srb->Buffer) {
/* this is a malloc'd renderbuffer (accum buffer) */
/* nothing to do */
return;
}
intel_miptree_unmap(brw, irb->mt, irb->mt_level, irb->mt_layer);
}
/**
* Round up the requested multisample count to the next supported sample size.
*/
unsigned
intel_quantize_num_samples(struct intel_screen *intel, unsigned num_samples)
{
switch (intel->gen) {
case 6:
/* Gen6 supports only 4x multisampling. */
if (num_samples > 0)
return 4;
else
return 0;
case 7:
/* Gen7 supports 4x and 8x multisampling. */
if (num_samples > 4)
return 8;
else if (num_samples > 0)
return 4;
else
return 0;
return 0;
default:
/* MSAA unsupported. */
return 0;
}
}
/**
* Called via glRenderbufferStorageEXT() to set the format and allocate
* storage for a user-created renderbuffer.
*/
static GLboolean
intel_alloc_renderbuffer_storage(struct gl_context * ctx, struct gl_renderbuffer *rb,
GLenum internalFormat,
GLuint width, GLuint height)
{
struct brw_context *brw = brw_context(ctx);
struct intel_screen *screen = brw->intelScreen;
struct intel_renderbuffer *irb = intel_renderbuffer(rb);
rb->NumSamples = intel_quantize_num_samples(screen, rb->NumSamples);
switch (internalFormat) {
default:
/* Use the same format-choice logic as for textures.
* Renderbuffers aren't any different from textures for us,
* except they're less useful because you can't texture with
* them.
*/
rb->Format = ctx->Driver.ChooseTextureFormat(ctx, GL_TEXTURE_2D,
internalFormat,
GL_NONE, GL_NONE);
break;
case GL_STENCIL_INDEX:
case GL_STENCIL_INDEX1_EXT:
case GL_STENCIL_INDEX4_EXT:
case GL_STENCIL_INDEX8_EXT:
case GL_STENCIL_INDEX16_EXT:
/* These aren't actual texture formats, so force them here. */
if (brw->has_separate_stencil) {
rb->Format = MESA_FORMAT_S8;
} else {
assert(!brw->must_use_separate_stencil);
rb->Format = MESA_FORMAT_S8_Z24;
}
break;
}
rb->Width = width;
rb->Height = height;
rb->_BaseFormat = _mesa_base_fbo_format(ctx, internalFormat);
intel_miptree_release(&irb->mt);
DBG("%s: %s: %s (%dx%d)\n", __FUNCTION__,
_mesa_lookup_enum_by_nr(internalFormat),
_mesa_get_format_name(rb->Format), width, height);
if (width == 0 || height == 0)
return true;
irb->mt = intel_miptree_create_for_renderbuffer(brw, rb->Format,
width, height,
rb->NumSamples);
if (!irb->mt)
return false;
return true;
}
static void
intel_image_target_renderbuffer_storage(struct gl_context *ctx,
struct gl_renderbuffer *rb,
void *image_handle)
{
struct brw_context *brw = brw_context(ctx);
struct intel_renderbuffer *irb;
__DRIscreen *screen;
__DRIimage *image;
screen = brw->intelScreen->driScrnPriv;
image = screen->dri2.image->lookupEGLImage(screen, image_handle,
screen->loaderPrivate);
if (image == NULL)
return;
/* __DRIimage is opaque to the core so it has to be checked here */
switch (image->format) {
case MESA_FORMAT_RGBA8888_REV:
_mesa_error(ctx, GL_INVALID_OPERATION,
"glEGLImageTargetRenderbufferStorage(unsupported image format");
return;
break;
default:
break;
}
irb = intel_renderbuffer(rb);
intel_miptree_release(&irb->mt);
irb->mt = intel_miptree_create_for_bo(brw,
image->region->bo,
image->format,
image->offset,
image->region->width,
image->region->height,
image->region->pitch,
image->region->tiling);
if (!irb->mt)
return;
rb->InternalFormat = image->internal_format;
rb->Width = image->region->width;
rb->Height = image->region->height;
rb->Format = image->format;
rb->_BaseFormat = _mesa_base_fbo_format(ctx, image->internal_format);
rb->NeedsFinishRenderTexture = true;
}
/**
* Called by _mesa_resize_framebuffer() for each hardware renderbuffer when a
* window system framebuffer is resized.
*
* Any actual buffer reallocations for hardware renderbuffers (which would
* have triggered _mesa_resize_framebuffer()) were done by
* intel_process_dri2_buffer().
*/
static GLboolean
intel_alloc_window_storage(struct gl_context * ctx, struct gl_renderbuffer *rb,
GLenum internalFormat, GLuint width, GLuint height)
{
ASSERT(rb->Name == 0);
rb->Width = width;
rb->Height = height;
rb->InternalFormat = internalFormat;
return true;
}
/** Dummy function for gl_renderbuffer::AllocStorage() */
static GLboolean
intel_nop_alloc_storage(struct gl_context * ctx, struct gl_renderbuffer *rb,
GLenum internalFormat, GLuint width, GLuint height)
{
_mesa_problem(ctx, "intel_op_alloc_storage should never be called.");
return false;
}
/**
* Create a new intel_renderbuffer which corresponds to an on-screen window,
* not a user-created renderbuffer.
*
* \param num_samples must be quantized.
*/
struct intel_renderbuffer *
intel_create_renderbuffer(gl_format format, unsigned num_samples)
{
struct intel_renderbuffer *irb;
struct gl_renderbuffer *rb;
ENTER();
GET_CURRENT_CONTEXT(ctx);
irb = CALLOC_STRUCT(intel_renderbuffer);
if (!irb) {
_mesa_error(ctx, GL_OUT_OF_MEMORY, "creating renderbuffer");
return NULL;
}
rb = &irb->Base.Base;
_mesa_init_renderbuffer(rb, 0);
rb->ClassID = INTEL_RB_CLASS;
rb->_BaseFormat = _mesa_get_format_base_format(format);
rb->Format = format;
rb->InternalFormat = rb->_BaseFormat;
rb->NumSamples = num_samples;
/* intel-specific methods */
rb->Delete = intel_delete_renderbuffer;
rb->AllocStorage = intel_alloc_window_storage;
LEAVE();
return irb;
}
/**
* Private window-system buffers (as opposed to ones shared with the display
* server created with intel_create_renderbuffer()) are most similar in their
* handling to user-created renderbuffers, but they have a resize handler that
* may be called at intel_update_renderbuffers() time.
*
* \param num_samples must be quantized.
*/
struct intel_renderbuffer *
intel_create_private_renderbuffer(gl_format format, unsigned num_samples)
{
struct intel_renderbuffer *irb;
irb = intel_create_renderbuffer(format, num_samples);
irb->Base.Base.AllocStorage = intel_alloc_renderbuffer_storage;
return irb;
}
/**
* Create a new renderbuffer object.
* Typically called via glBindRenderbufferEXT().
*/
static struct gl_renderbuffer *
intel_new_renderbuffer(struct gl_context * ctx, GLuint name)
{
struct intel_renderbuffer *irb;
struct gl_renderbuffer *rb;
irb = CALLOC_STRUCT(intel_renderbuffer);
if (!irb) {
_mesa_error(ctx, GL_OUT_OF_MEMORY, "creating renderbuffer");
return NULL;
}
rb = &irb->Base.Base;
_mesa_init_renderbuffer(rb, name);
rb->ClassID = INTEL_RB_CLASS;
/* intel-specific methods */
rb->Delete = intel_delete_renderbuffer;
rb->AllocStorage = intel_alloc_renderbuffer_storage;
/* span routines set in alloc_storage function */
return rb;
}
static bool
intel_renderbuffer_update_wrapper(struct brw_context *brw,
struct intel_renderbuffer *irb,
struct gl_texture_image *image,
uint32_t layer)
{
struct gl_renderbuffer *rb = &irb->Base.Base;
struct intel_texture_image *intel_image = intel_texture_image(image);
struct intel_mipmap_tree *mt = intel_image->mt;
int level = image->Level;
rb->Depth = image->Depth;
rb->AllocStorage = intel_nop_alloc_storage;
intel_miptree_check_level_layer(mt, level, layer);
irb->mt_level = level;
switch (mt->msaa_layout) {
case INTEL_MSAA_LAYOUT_UMS:
case INTEL_MSAA_LAYOUT_CMS:
irb->mt_layer = layer * mt->num_samples;
break;
default:
irb->mt_layer = layer;
}
intel_miptree_reference(&irb->mt, mt);
intel_renderbuffer_set_draw_offset(irb);
if (mt->hiz_mt == NULL && brw_is_hiz_depth_format(brw, rb->Format)) {
intel_miptree_alloc_hiz(brw, mt);
if (!mt->hiz_mt)
return false;
}
return true;
}
void
intel_renderbuffer_set_draw_offset(struct intel_renderbuffer *irb)
{
unsigned int dst_x, dst_y;
/* compute offset of the particular 2D image within the texture region */
intel_miptree_get_image_offset(irb->mt,
irb->mt_level,
irb->mt_layer,
&dst_x, &dst_y);
irb->draw_x = dst_x;
irb->draw_y = dst_y;
}
/**
* Called by glFramebufferTexture[123]DEXT() (and other places) to
* prepare for rendering into texture memory. This might be called
* many times to choose different texture levels, cube faces, etc
* before intel_finish_render_texture() is ever called.
*/
static void
intel_render_texture(struct gl_context * ctx,
struct gl_framebuffer *fb,
struct gl_renderbuffer_attachment *att)
{
struct brw_context *brw = brw_context(ctx);
struct gl_renderbuffer *rb = att->Renderbuffer;
struct intel_renderbuffer *irb = intel_renderbuffer(rb);
struct gl_texture_image *image = rb->TexImage;
struct intel_texture_image *intel_image = intel_texture_image(image);
struct intel_mipmap_tree *mt = intel_image->mt;
int layer;
(void) fb;
if (att->CubeMapFace > 0) {
assert(att->Zoffset == 0);
layer = att->CubeMapFace;
} else {
layer = att->Zoffset;
}
if (!intel_image->mt) {
/* Fallback on drawing to a texture that doesn't have a miptree
* (has a border, width/height 0, etc.)
*/
_swrast_render_texture(ctx, fb, att);
return;
}
intel_miptree_check_level_layer(mt, att->TextureLevel, layer);
if (!intel_renderbuffer_update_wrapper(brw, irb, image, layer)) {
_swrast_render_texture(ctx, fb, att);
return;
}
DBG("Begin render %s texture tex=%u w=%d h=%d d=%d refcount=%d\n",
_mesa_get_format_name(image->TexFormat),
att->Texture->Name, image->Width, image->Height, image->Depth,
rb->RefCount);
}
/**
* Called by Mesa when rendering to a texture is done.
*/
static void
intel_finish_render_texture(struct gl_context * ctx, struct gl_renderbuffer *rb)
{
struct brw_context *brw = brw_context(ctx);
DBG("Finish render %s texture\n", _mesa_get_format_name(rb->Format));
/* Since we've (probably) rendered to the texture and will (likely) use
* it in the texture domain later on in this batchbuffer, flush the
* batch. Once again, we wish for a domain tracker in libdrm to cover
* usage inside of a batchbuffer like GEM does in the kernel.
*/
intel_batchbuffer_emit_mi_flush(brw);
}
#define fbo_incomplete(fb, ...) do { \
static GLuint msg_id = 0; \
if (unlikely(ctx->Const.ContextFlags & GL_CONTEXT_FLAG_DEBUG_BIT)) { \
_mesa_gl_debug(ctx, &msg_id, \
MESA_DEBUG_TYPE_OTHER, \
MESA_DEBUG_SEVERITY_MEDIUM, \
__VA_ARGS__); \
} \
DBG(__VA_ARGS__); \
fb->_Status = GL_FRAMEBUFFER_UNSUPPORTED; \
} while (0)
/**
* Do additional "completeness" testing of a framebuffer object.
*/
static void
intel_validate_framebuffer(struct gl_context *ctx, struct gl_framebuffer *fb)
{
struct brw_context *brw = brw_context(ctx);
struct intel_renderbuffer *depthRb =
intel_get_renderbuffer(fb, BUFFER_DEPTH);
struct intel_renderbuffer *stencilRb =
intel_get_renderbuffer(fb, BUFFER_STENCIL);
struct intel_mipmap_tree *depth_mt = NULL, *stencil_mt = NULL;
int i;
DBG("%s() on fb %p (%s)\n", __FUNCTION__,
fb, (fb == ctx->DrawBuffer ? "drawbuffer" :
(fb == ctx->ReadBuffer ? "readbuffer" : "other buffer")));
if (depthRb)
depth_mt = depthRb->mt;
if (stencilRb) {
stencil_mt = stencilRb->mt;
if (stencil_mt->stencil_mt)
stencil_mt = stencil_mt->stencil_mt;
}
if (depth_mt && stencil_mt) {
if (depth_mt == stencil_mt) {
/* For true packed depth/stencil (not faked on prefers-separate-stencil
* hardware) we need to be sure they're the same level/layer, since
* we'll be emitting a single packet describing the packed setup.
*/
if (depthRb->mt_level != stencilRb->mt_level ||
depthRb->mt_layer != stencilRb->mt_layer) {
fbo_incomplete(fb,
"FBO incomplete: depth image level/layer %d/%d != "
"stencil image %d/%d\n",
depthRb->mt_level,
depthRb->mt_layer,
stencilRb->mt_level,
stencilRb->mt_layer);
}
} else {
if (!brw->has_separate_stencil) {
fbo_incomplete(fb, "FBO incomplete: separate stencil "
"unsupported\n");
}
if (stencil_mt->format != MESA_FORMAT_S8) {
fbo_incomplete(fb, "FBO incomplete: separate stencil is %s "
"instead of S8\n",
_mesa_get_format_name(stencil_mt->format));
}
if (brw->gen < 7 && !intel_renderbuffer_has_hiz(depthRb)) {
/* Before Gen7, separate depth and stencil buffers can be used
* only if HiZ is enabled. From the Sandybridge PRM, Volume 2,
* Part 1, Bit 3DSTATE_DEPTH_BUFFER.SeparateStencilBufferEnable:
* [DevSNB]: This field must be set to the same value (enabled
* or disabled) as Hierarchical Depth Buffer Enable.
*/
fbo_incomplete(fb, "FBO incomplete: separate stencil "
"without HiZ\n");
}
}
}
for (i = 0; i < Elements(fb->Attachment); i++) {
struct gl_renderbuffer *rb;
struct intel_renderbuffer *irb;
if (fb->Attachment[i].Type == GL_NONE)
continue;
/* A supported attachment will have a Renderbuffer set either
* from being a Renderbuffer or being a texture that got the
* intel_wrap_texture() treatment.
*/
rb = fb->Attachment[i].Renderbuffer;
if (rb == NULL) {
fbo_incomplete(fb, "FBO incomplete: attachment without "
"renderbuffer\n");
continue;
}
if (fb->Attachment[i].Type == GL_TEXTURE) {
if (rb->TexImage->Border) {
fbo_incomplete(fb, "FBO incomplete: texture with border\n");
continue;
}
}
irb = intel_renderbuffer(rb);
if (irb == NULL) {
fbo_incomplete(fb, "FBO incomplete: software rendering "
"renderbuffer\n");
continue;
}
if (!brw_render_target_supported(brw, rb)) {
fbo_incomplete(fb, "FBO incomplete: Unsupported HW "
"texture/renderbuffer format attached: %s\n",
_mesa_get_format_name(intel_rb_format(irb)));
}
}
}
/**
* Try to do a glBlitFramebuffer using glCopyTexSubImage2D
* We can do this when the dst renderbuffer is actually a texture and
* there is no scaling, mirroring or scissoring.
*
* \return new buffer mask indicating the buffers left to blit using the
* normal path.
*/
static GLbitfield
intel_blit_framebuffer_with_blitter(struct gl_context *ctx,
GLint srcX0, GLint srcY0,
GLint srcX1, GLint srcY1,
GLint dstX0, GLint dstY0,
GLint dstX1, GLint dstY1,
GLbitfield mask, GLenum filter)
{
struct brw_context *brw = brw_context(ctx);
/* Sync up the state of window system buffers. We need to do this before
* we go looking for the buffers.
*/
intel_prepare_render(brw);
if (mask & GL_COLOR_BUFFER_BIT) {
GLint i;
const struct gl_framebuffer *drawFb = ctx->DrawBuffer;
const struct gl_framebuffer *readFb = ctx->ReadBuffer;
struct gl_renderbuffer *src_rb = readFb->_ColorReadBuffer;
struct intel_renderbuffer *src_irb = intel_renderbuffer(src_rb);
if (!src_irb) {
perf_debug("glBlitFramebuffer(): missing src renderbuffer. "
"Falling back to software rendering.\n");
return mask;
}
/* If the source and destination are the same size with no mirroring,
* the rectangles are within the size of the texture and there is no
* scissor, then we can probably use the blit engine.
*/
if (!(srcX0 - srcX1 == dstX0 - dstX1 &&
srcY0 - srcY1 == dstY0 - dstY1 &&
srcX1 >= srcX0 &&
srcY1 >= srcY0 &&
srcX0 >= 0 && srcX1 <= readFb->Width &&
srcY0 >= 0 && srcY1 <= readFb->Height &&
dstX0 >= 0 && dstX1 <= drawFb->Width &&
dstY0 >= 0 && dstY1 <= drawFb->Height &&
!ctx->Scissor.Enabled)) {
perf_debug("glBlitFramebuffer(): non-1:1 blit. "
"Falling back to software rendering.\n");
return mask;
}
/* Blit to all active draw buffers. We don't do any pre-checking,
* because we assume that copying to MRTs is rare, and failure midway
* through copying is even more rare. Even if it was to occur, it's
* safe to let meta start the copy over from scratch, because
* glBlitFramebuffer completely overwrites the destination pixels, and
* results are undefined if any destination pixels have a dependency on
* source pixels.
*/
for (i = 0; i < ctx->DrawBuffer->_NumColorDrawBuffers; i++) {
struct gl_renderbuffer *dst_rb = ctx->DrawBuffer->_ColorDrawBuffers[i];
struct intel_renderbuffer *dst_irb = intel_renderbuffer(dst_rb);
if (!dst_irb) {
perf_debug("glBlitFramebuffer(): missing dst renderbuffer. "
"Falling back to software rendering.\n");
return mask;
}
gl_format src_format = _mesa_get_srgb_format_linear(src_rb->Format);
gl_format dst_format = _mesa_get_srgb_format_linear(dst_rb->Format);
if (src_format != dst_format) {
perf_debug("glBlitFramebuffer(): unsupported blit from %s to %s. "
"Falling back to software rendering.\n",
_mesa_get_format_name(src_format),
_mesa_get_format_name(dst_format));
return mask;
}
if (!intel_miptree_blit(brw,
src_irb->mt,
src_irb->mt_level, src_irb->mt_layer,
srcX0, srcY0, src_rb->Name == 0,
dst_irb->mt,
dst_irb->mt_level, dst_irb->mt_layer,
dstX0, dstY0, dst_rb->Name == 0,
dstX1 - dstX0, dstY1 - dstY0, GL_COPY)) {
perf_debug("glBlitFramebuffer(): unknown blit failure. "
"Falling back to software rendering.\n");
return mask;
}
}
mask &= ~GL_COLOR_BUFFER_BIT;
}
return mask;
}
static void
intel_blit_framebuffer(struct gl_context *ctx,
GLint srcX0, GLint srcY0, GLint srcX1, GLint srcY1,
GLint dstX0, GLint dstY0, GLint dstX1, GLint dstY1,
GLbitfield mask, GLenum filter)
{
mask = brw_blorp_framebuffer(brw_context(ctx),
srcX0, srcY0, srcX1, srcY1,
dstX0, dstY0, dstX1, dstY1,
mask, filter);
if (mask == 0x0)
return;
/* Try using the BLT engine. */
mask = intel_blit_framebuffer_with_blitter(ctx,
srcX0, srcY0, srcX1, srcY1,
dstX0, dstY0, dstX1, dstY1,
mask, filter);
if (mask == 0x0)
return;
_mesa_meta_BlitFramebuffer(ctx,
srcX0, srcY0, srcX1, srcY1,
dstX0, dstY0, dstX1, dstY1,
mask, filter);
}
/**
* This is a no-op except on multisample buffers shared with DRI2.
*/
void
intel_renderbuffer_set_needs_downsample(struct intel_renderbuffer *irb)
{
if (irb->mt && irb->mt->singlesample_mt)
irb->mt->need_downsample = true;
}
/**
* Does the renderbuffer have hiz enabled?
*/
bool
intel_renderbuffer_has_hiz(struct intel_renderbuffer *irb)
{
return intel_miptree_slice_has_hiz(irb->mt, irb->mt_level, irb->mt_layer);
}
void
intel_renderbuffer_set_needs_hiz_resolve(struct intel_renderbuffer *irb)
{
if (irb->mt) {
intel_miptree_slice_set_needs_hiz_resolve(irb->mt,
irb->mt_level,
irb->mt_layer);
}
}
void
intel_renderbuffer_set_needs_depth_resolve(struct intel_renderbuffer *irb)
{
if (irb->mt) {
intel_miptree_slice_set_needs_depth_resolve(irb->mt,
irb->mt_level,
irb->mt_layer);
}
}
bool
intel_renderbuffer_resolve_hiz(struct brw_context *brw,
struct intel_renderbuffer *irb)
{
if (irb->mt)
return intel_miptree_slice_resolve_hiz(brw,
irb->mt,
irb->mt_level,
irb->mt_layer);
return false;
}
bool
intel_renderbuffer_resolve_depth(struct brw_context *brw,
struct intel_renderbuffer *irb)
{
if (irb->mt)
return intel_miptree_slice_resolve_depth(brw,
irb->mt,
irb->mt_level,
irb->mt_layer);
return false;
}
void
intel_renderbuffer_move_to_temp(struct brw_context *brw,
struct intel_renderbuffer *irb,
bool invalidate)
{
struct gl_renderbuffer *rb =&irb->Base.Base;
struct intel_texture_image *intel_image = intel_texture_image(rb->TexImage);
struct intel_mipmap_tree *new_mt;
int width, height, depth;
intel_miptree_get_dimensions_for_image(rb->TexImage, &width, &height, &depth);
new_mt = intel_miptree_create(brw, rb->TexImage->TexObject->Target,
intel_image->base.Base.TexFormat,
intel_image->base.Base.Level,
intel_image->base.Base.Level,
width, height, depth,
true,
irb->mt->num_samples,
INTEL_MIPTREE_TILING_ANY);
if (brw_is_hiz_depth_format(brw, new_mt->format)) {
intel_miptree_alloc_hiz(brw, new_mt);
}
intel_miptree_copy_teximage(brw, intel_image, new_mt, invalidate);
intel_miptree_reference(&irb->mt, intel_image->mt);
intel_renderbuffer_set_draw_offset(irb);
intel_miptree_release(&new_mt);
}
/**
* Do one-time context initializations related to GL_EXT_framebuffer_object.
* Hook in device driver functions.
*/
void
intel_fbo_init(struct brw_context *brw)
{
struct dd_function_table *dd = &brw->ctx.Driver;
dd->NewFramebuffer = intel_new_framebuffer;
dd->NewRenderbuffer = intel_new_renderbuffer;
dd->MapRenderbuffer = intel_map_renderbuffer;
dd->UnmapRenderbuffer = intel_unmap_renderbuffer;
dd->RenderTexture = intel_render_texture;
dd->FinishRenderTexture = intel_finish_render_texture;
dd->ValidateFramebuffer = intel_validate_framebuffer;
dd->BlitFramebuffer = intel_blit_framebuffer;
dd->EGLImageTargetRenderbufferStorage =
intel_image_target_renderbuffer_storage;
}

View File

@ -1,589 +0,0 @@
/*
* Mesa 3-D graphics library
*
* Copyright (C) 1999-2007 Brian Paul 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.
*/
/**
* \file clear.c
* glClearColor, glClearIndex, glClear() functions.
*/
#include "glheader.h"
#include "clear.h"
#include "context.h"
#include "colormac.h"
#include "enums.h"
#include "macros.h"
#include "mtypes.h"
#include "state.h"
void GLAPIENTRY
_mesa_ClearIndex( GLfloat c )
{
GET_CURRENT_CONTEXT(ctx);
ctx->Color.ClearIndex = (GLuint) c;
}
/**
* Specify the clear values for the color buffers.
*
* \param red red color component.
* \param green green color component.
* \param blue blue color component.
* \param alpha alpha component.
*
* \sa glClearColor().
*
* Clamps the parameters and updates gl_colorbuffer_attrib::ClearColor. On a
* change, flushes the vertices and notifies the driver via the
* dd_function_table::ClearColor callback.
*/
void GLAPIENTRY
_mesa_ClearColor( GLclampf red, GLclampf green, GLclampf blue, GLclampf alpha )
{
GET_CURRENT_CONTEXT(ctx);
ctx->Color.ClearColor.f[0] = red;
ctx->Color.ClearColor.f[1] = green;
ctx->Color.ClearColor.f[2] = blue;
ctx->Color.ClearColor.f[3] = alpha;
}
/**
* GL_EXT_texture_integer
*/
void GLAPIENTRY
_mesa_ClearColorIiEXT(GLint r, GLint g, GLint b, GLint a)
{
GET_CURRENT_CONTEXT(ctx);
ctx->Color.ClearColor.i[0] = r;
ctx->Color.ClearColor.i[1] = g;
ctx->Color.ClearColor.i[2] = b;
ctx->Color.ClearColor.i[3] = a;
}
/**
* GL_EXT_texture_integer
*/
void GLAPIENTRY
_mesa_ClearColorIuiEXT(GLuint r, GLuint g, GLuint b, GLuint a)
{
GET_CURRENT_CONTEXT(ctx);
ctx->Color.ClearColor.ui[0] = r;
ctx->Color.ClearColor.ui[1] = g;
ctx->Color.ClearColor.ui[2] = b;
ctx->Color.ClearColor.ui[3] = a;
}
/**
* Clear buffers.
*
* \param mask bit-mask indicating the buffers to be cleared.
*
* Flushes the vertices and verifies the parameter. If __struct gl_contextRec::NewState
* is set then calls _mesa_update_state() to update gl_frame_buffer::_Xmin,
* etc. If the rasterization mode is set to GL_RENDER then requests the driver
* to clear the buffers, via the dd_function_table::Clear callback.
*/
void GLAPIENTRY
_mesa_Clear( GLbitfield mask )
{
GET_CURRENT_CONTEXT(ctx);
FLUSH_VERTICES(ctx, 0);
FLUSH_CURRENT(ctx, 0);
if (MESA_VERBOSE & VERBOSE_API)
_mesa_debug(ctx, "glClear 0x%x\n", mask);
if (mask & ~(GL_COLOR_BUFFER_BIT |
GL_DEPTH_BUFFER_BIT |
GL_STENCIL_BUFFER_BIT |
GL_ACCUM_BUFFER_BIT)) {
/* invalid bit set */
_mesa_error( ctx, GL_INVALID_VALUE, "glClear(0x%x)", mask);
return;
}
/* Accumulation buffers were removed in core contexts, and they never
* existed in OpenGL ES.
*/
if ((mask & GL_ACCUM_BUFFER_BIT) != 0
&& (ctx->API == API_OPENGL_CORE || _mesa_is_gles(ctx))) {
_mesa_error( ctx, GL_INVALID_VALUE, "glClear(GL_ACCUM_BUFFER_BIT)");
return;
}
if (ctx->NewState) {
_mesa_update_state( ctx ); /* update _Xmin, etc */
}
if (ctx->DrawBuffer->_Status != GL_FRAMEBUFFER_COMPLETE_EXT) {
_mesa_error(ctx, GL_INVALID_FRAMEBUFFER_OPERATION_EXT,
"glClear(incomplete framebuffer)");
return;
}
if (ctx->DrawBuffer->Width == 0 || ctx->DrawBuffer->Height == 0 ||
ctx->DrawBuffer->_Xmin >= ctx->DrawBuffer->_Xmax ||
ctx->DrawBuffer->_Ymin >= ctx->DrawBuffer->_Ymax)
return;
if (ctx->RasterDiscard)
return;
if (ctx->RenderMode == GL_RENDER) {
GLbitfield bufferMask;
/* don't clear depth buffer if depth writing disabled */
if (!ctx->Depth.Mask)
mask &= ~GL_DEPTH_BUFFER_BIT;
/* Build the bitmask to send to device driver's Clear function.
* Note that the GL_COLOR_BUFFER_BIT flag will expand to 0, 1, 2 or 4
* of the BUFFER_BIT_FRONT/BACK_LEFT/RIGHT flags, or one of the
* BUFFER_BIT_COLORn flags.
*/
bufferMask = 0;
if (mask & GL_COLOR_BUFFER_BIT) {
GLuint i;
for (i = 0; i < ctx->DrawBuffer->_NumColorDrawBuffers; i++) {
bufferMask |= (1 << ctx->DrawBuffer->_ColorDrawBufferIndexes[i]);
}
}
if ((mask & GL_DEPTH_BUFFER_BIT)
&& ctx->DrawBuffer->Visual.haveDepthBuffer) {
bufferMask |= BUFFER_BIT_DEPTH;
}
if ((mask & GL_STENCIL_BUFFER_BIT)
&& ctx->DrawBuffer->Visual.haveStencilBuffer) {
bufferMask |= BUFFER_BIT_STENCIL;
}
if ((mask & GL_ACCUM_BUFFER_BIT)
&& ctx->DrawBuffer->Visual.haveAccumBuffer) {
bufferMask |= BUFFER_BIT_ACCUM;
}
ASSERT(ctx->Driver.Clear);
ctx->Driver.Clear(ctx, bufferMask);
}
LEAVE();
}
/** Returned by make_color_buffer_mask() for errors */
#define INVALID_MASK ~0x0
/**
* Convert the glClearBuffer 'drawbuffer' parameter into a bitmask of
* BUFFER_BIT_x values.
* Return INVALID_MASK if the drawbuffer value is invalid.
*/
static GLbitfield
make_color_buffer_mask(struct gl_context *ctx, GLint drawbuffer)
{
const struct gl_renderbuffer_attachment *att = ctx->DrawBuffer->Attachment;
GLbitfield mask = 0x0;
switch (drawbuffer) {
case GL_FRONT:
if (att[BUFFER_FRONT_LEFT].Renderbuffer)
mask |= BUFFER_BIT_FRONT_LEFT;
if (att[BUFFER_FRONT_RIGHT].Renderbuffer)
mask |= BUFFER_BIT_FRONT_RIGHT;
break;
case GL_BACK:
if (att[BUFFER_BACK_LEFT].Renderbuffer)
mask |= BUFFER_BIT_BACK_LEFT;
if (att[BUFFER_BACK_RIGHT].Renderbuffer)
mask |= BUFFER_BIT_BACK_RIGHT;
break;
case GL_LEFT:
if (att[BUFFER_FRONT_LEFT].Renderbuffer)
mask |= BUFFER_BIT_FRONT_LEFT;
if (att[BUFFER_BACK_LEFT].Renderbuffer)
mask |= BUFFER_BIT_BACK_LEFT;
break;
case GL_RIGHT:
if (att[BUFFER_FRONT_RIGHT].Renderbuffer)
mask |= BUFFER_BIT_FRONT_RIGHT;
if (att[BUFFER_BACK_RIGHT].Renderbuffer)
mask |= BUFFER_BIT_BACK_RIGHT;
break;
case GL_FRONT_AND_BACK:
if (att[BUFFER_FRONT_LEFT].Renderbuffer)
mask |= BUFFER_BIT_FRONT_LEFT;
if (att[BUFFER_BACK_LEFT].Renderbuffer)
mask |= BUFFER_BIT_BACK_LEFT;
if (att[BUFFER_FRONT_RIGHT].Renderbuffer)
mask |= BUFFER_BIT_FRONT_RIGHT;
if (att[BUFFER_BACK_RIGHT].Renderbuffer)
mask |= BUFFER_BIT_BACK_RIGHT;
break;
default:
if (drawbuffer < 0 || drawbuffer >= (GLint)ctx->Const.MaxDrawBuffers) {
mask = INVALID_MASK;
}
else if (att[BUFFER_COLOR0 + drawbuffer].Renderbuffer) {
mask |= (BUFFER_BIT_COLOR0 << drawbuffer);
}
}
return mask;
}
/**
* New in GL 3.0
* Clear signed integer color buffer or stencil buffer (not depth).
*/
void GLAPIENTRY
_mesa_ClearBufferiv(GLenum buffer, GLint drawbuffer, const GLint *value)
{
GET_CURRENT_CONTEXT(ctx);
FLUSH_VERTICES(ctx, 0);
FLUSH_CURRENT(ctx, 0);
if (ctx->NewState) {
_mesa_update_state( ctx );
}
switch (buffer) {
case GL_STENCIL:
/* Page 264 (page 280 of the PDF) of the OpenGL 3.0 spec says:
*
* "ClearBuffer generates an INVALID VALUE error if buffer is
* COLOR and drawbuffer is less than zero, or greater than the
* value of MAX DRAW BUFFERS minus one; or if buffer is DEPTH,
* STENCIL, or DEPTH STENCIL and drawbuffer is not zero."
*/
if (drawbuffer != 0) {
_mesa_error(ctx, GL_INVALID_VALUE, "glClearBufferiv(drawbuffer=%d)",
drawbuffer);
return;
}
else if (ctx->DrawBuffer->Attachment[BUFFER_STENCIL].Renderbuffer && !ctx->RasterDiscard) {
/* Save current stencil clear value, set to 'value', do the
* stencil clear and restore the clear value.
* XXX in the future we may have a new ctx->Driver.ClearBuffer()
* hook instead.
*/
const GLuint clearSave = ctx->Stencil.Clear;
ctx->Stencil.Clear = *value;
ctx->Driver.Clear(ctx, BUFFER_BIT_STENCIL);
ctx->Stencil.Clear = clearSave;
}
break;
case GL_COLOR:
{
const GLbitfield mask = make_color_buffer_mask(ctx, drawbuffer);
if (mask == INVALID_MASK) {
_mesa_error(ctx, GL_INVALID_VALUE, "glClearBufferiv(drawbuffer=%d)",
drawbuffer);
return;
}
else if (mask && !ctx->RasterDiscard) {
union gl_color_union clearSave;
/* save color */
clearSave = ctx->Color.ClearColor;
/* set color */
COPY_4V(ctx->Color.ClearColor.i, value);
/* clear buffer(s) */
ctx->Driver.Clear(ctx, mask);
/* restore color */
ctx->Color.ClearColor = clearSave;
}
}
break;
case GL_DEPTH:
/* Page 264 (page 280 of the PDF) of the OpenGL 3.0 spec says:
*
* "The result of ClearBuffer is undefined if no conversion between
* the type of the specified value and the type of the buffer being
* cleared is defined (for example, if ClearBufferiv is called for a
* fixed- or floating-point buffer, or if ClearBufferfv is called
* for a signed or unsigned integer buffer). This is not an error."
*
* In this case we take "undefined" and "not an error" to mean "ignore."
* Note that we still need to generate an error for the invalid
* drawbuffer case (see the GL_STENCIL case above).
*/
if (drawbuffer != 0) {
_mesa_error(ctx, GL_INVALID_VALUE, "glClearBufferiv(drawbuffer=%d)",
drawbuffer);
return;
}
return;
default:
_mesa_error(ctx, GL_INVALID_ENUM, "glClearBufferiv(buffer=%s)",
_mesa_lookup_enum_by_nr(buffer));
return;
}
}
/**
* New in GL 3.0
* Clear unsigned integer color buffer (not depth, not stencil).
*/
void GLAPIENTRY
_mesa_ClearBufferuiv(GLenum buffer, GLint drawbuffer, const GLuint *value)
{
GET_CURRENT_CONTEXT(ctx);
FLUSH_VERTICES(ctx, 0);
FLUSH_CURRENT(ctx, 0);
if (ctx->NewState) {
_mesa_update_state( ctx );
}
switch (buffer) {
case GL_COLOR:
{
const GLbitfield mask = make_color_buffer_mask(ctx, drawbuffer);
if (mask == INVALID_MASK) {
_mesa_error(ctx, GL_INVALID_VALUE, "glClearBufferuiv(drawbuffer=%d)",
drawbuffer);
return;
}
else if (mask && !ctx->RasterDiscard) {
union gl_color_union clearSave;
/* save color */
clearSave = ctx->Color.ClearColor;
/* set color */
COPY_4V(ctx->Color.ClearColor.ui, value);
/* clear buffer(s) */
ctx->Driver.Clear(ctx, mask);
/* restore color */
ctx->Color.ClearColor = clearSave;
}
}
break;
case GL_DEPTH:
case GL_STENCIL:
/* Page 264 (page 280 of the PDF) of the OpenGL 3.0 spec says:
*
* "The result of ClearBuffer is undefined if no conversion between
* the type of the specified value and the type of the buffer being
* cleared is defined (for example, if ClearBufferiv is called for a
* fixed- or floating-point buffer, or if ClearBufferfv is called
* for a signed or unsigned integer buffer). This is not an error."
*
* In this case we take "undefined" and "not an error" to mean "ignore."
* Even though we could do something sensible for GL_STENCIL, page 263
* (page 279 of the PDF) says:
*
* "Only ClearBufferiv should be used to clear stencil buffers."
*
* Note that we still need to generate an error for the invalid
* drawbuffer case (see the GL_STENCIL case in _mesa_ClearBufferiv).
*/
if (drawbuffer != 0) {
_mesa_error(ctx, GL_INVALID_VALUE, "glClearBufferuiv(drawbuffer=%d)",
drawbuffer);
return;
}
return;
default:
_mesa_error(ctx, GL_INVALID_ENUM, "glClearBufferuiv(buffer=%s)",
_mesa_lookup_enum_by_nr(buffer));
return;
}
}
/**
* New in GL 3.0
* Clear fixed-pt or float color buffer or depth buffer (not stencil).
*/
void GLAPIENTRY
_mesa_ClearBufferfv(GLenum buffer, GLint drawbuffer, const GLfloat *value)
{
GET_CURRENT_CONTEXT(ctx);
FLUSH_VERTICES(ctx, 0);
FLUSH_CURRENT(ctx, 0);
if (ctx->NewState) {
_mesa_update_state( ctx );
}
switch (buffer) {
case GL_DEPTH:
/* Page 264 (page 280 of the PDF) of the OpenGL 3.0 spec says:
*
* "ClearBuffer generates an INVALID VALUE error if buffer is
* COLOR and drawbuffer is less than zero, or greater than the
* value of MAX DRAW BUFFERS minus one; or if buffer is DEPTH,
* STENCIL, or DEPTH STENCIL and drawbuffer is not zero."
*/
if (drawbuffer != 0) {
_mesa_error(ctx, GL_INVALID_VALUE, "glClearBufferfv(drawbuffer=%d)",
drawbuffer);
return;
}
else if (ctx->DrawBuffer->Attachment[BUFFER_DEPTH].Renderbuffer && !ctx->RasterDiscard) {
/* Save current depth clear value, set to 'value', do the
* depth clear and restore the clear value.
* XXX in the future we may have a new ctx->Driver.ClearBuffer()
* hook instead.
*/
const GLclampd clearSave = ctx->Depth.Clear;
ctx->Depth.Clear = *value;
ctx->Driver.Clear(ctx, BUFFER_BIT_DEPTH);
ctx->Depth.Clear = clearSave;
}
/* clear depth buffer to value */
break;
case GL_COLOR:
{
const GLbitfield mask = make_color_buffer_mask(ctx, drawbuffer);
if (mask == INVALID_MASK) {
_mesa_error(ctx, GL_INVALID_VALUE, "glClearBufferfv(drawbuffer=%d)",
drawbuffer);
return;
}
else if (mask && !ctx->RasterDiscard) {
union gl_color_union clearSave;
/* save color */
clearSave = ctx->Color.ClearColor;
/* set color */
COPY_4V(ctx->Color.ClearColor.f, value);
/* clear buffer(s) */
ctx->Driver.Clear(ctx, mask);
/* restore color */
ctx->Color.ClearColor = clearSave;
}
}
break;
case GL_STENCIL:
/* Page 264 (page 280 of the PDF) of the OpenGL 3.0 spec says:
*
* "The result of ClearBuffer is undefined if no conversion between
* the type of the specified value and the type of the buffer being
* cleared is defined (for example, if ClearBufferiv is called for a
* fixed- or floating-point buffer, or if ClearBufferfv is called
* for a signed or unsigned integer buffer). This is not an error."
*
* In this case we take "undefined" and "not an error" to mean "ignore."
* Note that we still need to generate an error for the invalid
* drawbuffer case (see the GL_DEPTH case above).
*/
if (drawbuffer != 0) {
_mesa_error(ctx, GL_INVALID_VALUE, "glClearBufferfv(drawbuffer=%d)",
drawbuffer);
return;
}
return;
default:
_mesa_error(ctx, GL_INVALID_ENUM, "glClearBufferfv(buffer=%s)",
_mesa_lookup_enum_by_nr(buffer));
return;
}
}
/**
* New in GL 3.0
* Clear depth/stencil buffer only.
*/
void GLAPIENTRY
_mesa_ClearBufferfi(GLenum buffer, GLint drawbuffer,
GLfloat depth, GLint stencil)
{
GET_CURRENT_CONTEXT(ctx);
GLbitfield mask = 0;
FLUSH_VERTICES(ctx, 0);
FLUSH_CURRENT(ctx, 0);
if (buffer != GL_DEPTH_STENCIL) {
_mesa_error(ctx, GL_INVALID_ENUM, "glClearBufferfi(buffer=%s)",
_mesa_lookup_enum_by_nr(buffer));
return;
}
/* Page 264 (page 280 of the PDF) of the OpenGL 3.0 spec says:
*
* "ClearBuffer generates an INVALID VALUE error if buffer is
* COLOR and drawbuffer is less than zero, or greater than the
* value of MAX DRAW BUFFERS minus one; or if buffer is DEPTH,
* STENCIL, or DEPTH STENCIL and drawbuffer is not zero."
*/
if (drawbuffer != 0) {
_mesa_error(ctx, GL_INVALID_VALUE, "glClearBufferfi(drawbuffer=%d)",
drawbuffer);
return;
}
if (ctx->RasterDiscard)
return;
if (ctx->NewState) {
_mesa_update_state( ctx );
}
if (ctx->DrawBuffer->Attachment[BUFFER_DEPTH].Renderbuffer)
mask |= BUFFER_BIT_DEPTH;
if (ctx->DrawBuffer->Attachment[BUFFER_STENCIL].Renderbuffer)
mask |= BUFFER_BIT_STENCIL;
if (mask) {
/* save current clear values */
const GLclampd clearDepthSave = ctx->Depth.Clear;
const GLuint clearStencilSave = ctx->Stencil.Clear;
/* set new clear values */
ctx->Depth.Clear = depth;
ctx->Stencil.Clear = stencil;
/* clear buffers */
ctx->Driver.Clear(ctx, mask);
/* restore */
ctx->Depth.Clear = clearDepthSave;
ctx->Stencil.Clear = clearStencilSave;
}
}

File diff suppressed because it is too large Load Diff

View File

@ -1,85 +0,0 @@
/*
* Mesa 3-D graphics library
*
* Copyright (C) 2009 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 "main/compiler.h"
#include "main/cpuinfo.h"
/**
* This function should be called before the various "cpu_has_foo" macros
* are used.
*/
void
_mesa_get_cpu_features(void)
{
#ifdef USE_X86_ASM
_mesa_get_x86_features();
#endif
}
/**
* Return a string describing the CPU architexture and extensions that
* Mesa is using (such as SSE or Altivec).
* \return information string, free it with free()
*/
char *
_mesa_get_cpu_string(void)
{
#define MAX_STRING 50
char *buffer;
buffer = malloc(MAX_STRING);
if (!buffer)
return NULL;
buffer[0] = 0;
#ifdef USE_X86_ASM
if (_mesa_x86_cpu_features) {
strcat(buffer, "x86");
}
# ifdef USE_MMX_ASM
if (cpu_has_mmx) {
strcat(buffer, (cpu_has_mmxext) ? "/MMX+" : "/MMX");
}
# endif
# ifdef USE_3DNOW_ASM
if (cpu_has_3dnow) {
strcat(buffer, (cpu_has_3dnowext) ? "/3DNow!+" : "/3DNow!");
}
# endif
# ifdef USE_SSE_ASM
if (cpu_has_xmm) {
strcat(buffer, (cpu_has_xmm2) ? "/SSE2" : "/SSE");
}
# endif
assert(strlen(buffer) < MAX_STRING);
return buffer;
}

View File

@ -1,513 +0,0 @@
/*
* Mesa 3-D graphics library
*
* Copyright (C) 1999-2008 Brian Paul 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.
*/
/**
* \file state.c
* State management.
*
* This file manages recalculation of derived values in struct gl_context.
*/
#include "glheader.h"
#include "mtypes.h"
#include "arrayobj.h"
#include "context.h"
#include "debug.h"
#include "macros.h"
#include "ffvertex_prog.h"
#include "framebuffer.h"
#include "light.h"
#include "matrix.h"
#include "pixel.h"
#include "program/program.h"
#include "program/prog_parameter.h"
#include "shaderobj.h"
#include "state.h"
#include "stencil.h"
#include "texenvprogram.h"
#include "texobj.h"
#include "texstate.h"
#include "varray.h"
#include "blend.h"
/**
* Update the following fields:
* ctx->VertexProgram._Enabled
* ctx->FragmentProgram._Enabled
* ctx->ATIFragmentShader._Enabled
* This needs to be done before texture state validation.
*/
static void
update_program_enables(struct gl_context *ctx)
{
/* These _Enabled flags indicate if the user-defined ARB/NV vertex/fragment
* program is enabled AND valid. Similarly for ATI fragment shaders.
* GLSL shaders not relevant here.
*/
ctx->VertexProgram._Enabled = ctx->VertexProgram.Enabled
&& ctx->VertexProgram.Current->Base.Instructions;
ctx->FragmentProgram._Enabled = ctx->FragmentProgram.Enabled
&& ctx->FragmentProgram.Current->Base.Instructions;
ctx->ATIFragmentShader._Enabled = ctx->ATIFragmentShader.Enabled
&& ctx->ATIFragmentShader.Current->Instructions[0];
}
/**
* Update the ctx->Vertex/Geometry/FragmentProgram._Current pointers to point
* to the current/active programs. Then call ctx->Driver.BindProgram() to
* tell the driver which programs to use.
*
* Programs may come from 3 sources: GLSL shaders, ARB/NV_vertex/fragment
* programs or programs derived from fixed-function state.
*
* This function needs to be called after texture state validation in case
* we're generating a fragment program from fixed-function texture state.
*
* \return bitfield which will indicate _NEW_PROGRAM state if a new vertex
* or fragment program is being used.
*/
static GLbitfield
update_program(struct gl_context *ctx)
{
const struct gl_shader_program *vsProg = ctx->Shader.CurrentVertexProgram;
const struct gl_shader_program *gsProg = ctx->Shader.CurrentGeometryProgram;
struct gl_shader_program *fsProg = ctx->Shader.CurrentFragmentProgram;
const struct gl_vertex_program *prevVP = ctx->VertexProgram._Current;
const struct gl_fragment_program *prevFP = ctx->FragmentProgram._Current;
const struct gl_geometry_program *prevGP = ctx->GeometryProgram._Current;
GLbitfield new_state = 0x0;
/*
* Set the ctx->VertexProgram._Current and ctx->FragmentProgram._Current
* pointers to the programs that should be used for rendering. If either
* is NULL, use fixed-function code paths.
*
* These programs may come from several sources. The priority is as
* follows:
* 1. OpenGL 2.0/ARB vertex/fragment shaders
* 2. ARB/NV vertex/fragment programs
* 3. Programs derived from fixed-function state.
*
* Note: it's possible for a vertex shader to get used with a fragment
* program (and vice versa) here, but in practice that shouldn't ever
* come up, or matter.
*/
if (fsProg && fsProg->LinkStatus
&& fsProg->_LinkedShaders[MESA_SHADER_FRAGMENT]) {
/* Use GLSL fragment shader */
_mesa_reference_shader_program(ctx,
&ctx->Shader._CurrentFragmentProgram,
fsProg);
_mesa_reference_fragprog(ctx, &ctx->FragmentProgram._Current,
gl_fragment_program(fsProg->_LinkedShaders[MESA_SHADER_FRAGMENT]->Program));
_mesa_reference_fragprog(ctx, &ctx->FragmentProgram._TexEnvProgram,
NULL);
}
else if (ctx->FragmentProgram._Enabled) {
/* Use user-defined fragment program */
_mesa_reference_shader_program(ctx,
&ctx->Shader._CurrentFragmentProgram,
NULL);
_mesa_reference_fragprog(ctx, &ctx->FragmentProgram._Current,
ctx->FragmentProgram.Current);
_mesa_reference_fragprog(ctx, &ctx->FragmentProgram._TexEnvProgram,
NULL);
}
else if (ctx->FragmentProgram._MaintainTexEnvProgram) {
/* Use fragment program generated from fixed-function state */
struct gl_shader_program *f = _mesa_get_fixed_func_fragment_program(ctx);
_mesa_reference_shader_program(ctx,
&ctx->Shader._CurrentFragmentProgram,
f);
_mesa_reference_fragprog(ctx, &ctx->FragmentProgram._Current,
gl_fragment_program(f->_LinkedShaders[MESA_SHADER_FRAGMENT]->Program));
_mesa_reference_fragprog(ctx, &ctx->FragmentProgram._TexEnvProgram,
gl_fragment_program(f->_LinkedShaders[MESA_SHADER_FRAGMENT]->Program));
}
else {
/* No fragment program */
_mesa_reference_fragprog(ctx, &ctx->FragmentProgram._Current, NULL);
_mesa_reference_fragprog(ctx, &ctx->FragmentProgram._TexEnvProgram,
NULL);
}
if (gsProg && gsProg->LinkStatus
&& gsProg->_LinkedShaders[MESA_SHADER_GEOMETRY]) {
/* Use GLSL geometry shader */
_mesa_reference_geomprog(ctx, &ctx->GeometryProgram._Current,
gl_geometry_program(gsProg->_LinkedShaders[MESA_SHADER_GEOMETRY]->Program));
} else {
/* No geometry program */
_mesa_reference_geomprog(ctx, &ctx->GeometryProgram._Current, NULL);
}
/* Examine vertex program after fragment program as
* _mesa_get_fixed_func_vertex_program() needs to know active
* fragprog inputs.
*/
if (vsProg && vsProg->LinkStatus
&& vsProg->_LinkedShaders[MESA_SHADER_VERTEX]) {
/* Use GLSL vertex shader */
_mesa_reference_vertprog(ctx, &ctx->VertexProgram._Current,
gl_vertex_program(vsProg->_LinkedShaders[MESA_SHADER_VERTEX]->Program));
}
else if (ctx->VertexProgram._Enabled) {
/* Use user-defined vertex program */
_mesa_reference_vertprog(ctx, &ctx->VertexProgram._Current,
ctx->VertexProgram.Current);
}
else if (ctx->VertexProgram._MaintainTnlProgram) {
/* Use vertex program generated from fixed-function state */
_mesa_reference_vertprog(ctx, &ctx->VertexProgram._Current,
_mesa_get_fixed_func_vertex_program(ctx));
_mesa_reference_vertprog(ctx, &ctx->VertexProgram._TnlProgram,
ctx->VertexProgram._Current);
}
else {
/* no vertex program */
_mesa_reference_vertprog(ctx, &ctx->VertexProgram._Current, NULL);
}
/* Let the driver know what's happening:
*/
if (ctx->FragmentProgram._Current != prevFP) {
new_state |= _NEW_PROGRAM;
if (ctx->Driver.BindProgram) {
ctx->Driver.BindProgram(ctx, GL_FRAGMENT_PROGRAM_ARB,
(struct gl_program *) ctx->FragmentProgram._Current);
}
}
if (ctx->GeometryProgram._Current != prevGP) {
new_state |= _NEW_PROGRAM;
if (ctx->Driver.BindProgram) {
ctx->Driver.BindProgram(ctx, MESA_GEOMETRY_PROGRAM,
(struct gl_program *) ctx->GeometryProgram._Current);
}
}
if (ctx->VertexProgram._Current != prevVP) {
new_state |= _NEW_PROGRAM;
if (ctx->Driver.BindProgram) {
ctx->Driver.BindProgram(ctx, GL_VERTEX_PROGRAM_ARB,
(struct gl_program *) ctx->VertexProgram._Current);
}
}
return new_state;
}
/**
* Examine shader constants and return either _NEW_PROGRAM_CONSTANTS or 0.
*/
static GLbitfield
update_program_constants(struct gl_context *ctx)
{
GLbitfield new_state = 0x0;
if (ctx->FragmentProgram._Current) {
const struct gl_program_parameter_list *params =
ctx->FragmentProgram._Current->Base.Parameters;
if (params && params->StateFlags & ctx->NewState) {
new_state |= _NEW_PROGRAM_CONSTANTS;
}
}
if (ctx->GeometryProgram._Current) {
const struct gl_program_parameter_list *params =
ctx->GeometryProgram._Current->Base.Parameters;
/*FIXME: StateFlags is always 0 because we have unnamed constant
* not state changes */
if (params /*&& params->StateFlags & ctx->NewState*/) {
new_state |= _NEW_PROGRAM_CONSTANTS;
}
}
if (ctx->VertexProgram._Current) {
const struct gl_program_parameter_list *params =
ctx->VertexProgram._Current->Base.Parameters;
if (params && params->StateFlags & ctx->NewState) {
new_state |= _NEW_PROGRAM_CONSTANTS;
}
}
return new_state;
}
static void
update_viewport_matrix(struct gl_context *ctx)
{
const GLfloat depthMax = ctx->DrawBuffer->_DepthMaxF;
ASSERT(depthMax > 0);
/* Compute scale and bias values. This is really driver-specific
* and should be maintained elsewhere if at all.
* NOTE: RasterPos uses this.
*/
_math_matrix_viewport(&ctx->Viewport._WindowMap,
ctx->Viewport.X, ctx->Viewport.Y,
ctx->Viewport.Width, ctx->Viewport.Height,
ctx->Viewport.Near, ctx->Viewport.Far,
depthMax);
}
/**
* Update derived multisample state.
*/
static void
update_multisample(struct gl_context *ctx)
{
ctx->Multisample._Enabled = GL_FALSE;
if (ctx->Multisample.Enabled &&
ctx->DrawBuffer &&
ctx->DrawBuffer->Visual.sampleBuffers)
ctx->Multisample._Enabled = GL_TRUE;
}
/**
* Update the ctx->VertexProgram._TwoSideEnabled flag.
*/
static void
update_twoside(struct gl_context *ctx)
{
if (ctx->Shader.CurrentVertexProgram ||
ctx->VertexProgram._Enabled) {
ctx->VertexProgram._TwoSideEnabled = ctx->VertexProgram.TwoSideEnabled;
} else {
ctx->VertexProgram._TwoSideEnabled = (ctx->Light.Enabled &&
ctx->Light.Model.TwoSide);
}
}
/**
* Compute derived GL state.
* If __struct gl_contextRec::NewState is non-zero then this function \b must
* be called before rendering anything.
*
* Calls dd_function_table::UpdateState to perform any internal state
* management necessary.
*
* \sa _mesa_update_modelview_project(), _mesa_update_texture(),
* _mesa_update_buffer_bounds(),
* _mesa_update_lighting() and _mesa_update_tnl_spaces().
*/
void
_mesa_update_state_locked( struct gl_context *ctx )
{
GLbitfield new_state = ctx->NewState;
GLbitfield prog_flags = _NEW_PROGRAM;
GLbitfield new_prog_state = 0x0;
if (new_state == _NEW_CURRENT_ATTRIB)
goto out;
if (MESA_VERBOSE & VERBOSE_STATE)
_mesa_print_state("_mesa_update_state", new_state);
/* Determine which state flags effect vertex/fragment program state */
if (ctx->FragmentProgram._MaintainTexEnvProgram) {
prog_flags |= (_NEW_BUFFERS | _NEW_TEXTURE | _NEW_FOG |
_NEW_VARYING_VP_INPUTS | _NEW_LIGHT | _NEW_POINT |
_NEW_RENDERMODE | _NEW_PROGRAM | _NEW_FRAG_CLAMP |
_NEW_COLOR);
}
if (ctx->VertexProgram._MaintainTnlProgram) {
prog_flags |= (_NEW_VARYING_VP_INPUTS | _NEW_TEXTURE |
_NEW_TEXTURE_MATRIX | _NEW_TRANSFORM | _NEW_POINT |
_NEW_FOG | _NEW_LIGHT |
_MESA_NEW_NEED_EYE_COORDS);
}
/*
* Now update derived state info
*/
if (new_state & prog_flags)
update_program_enables( ctx );
if (new_state & (_NEW_MODELVIEW|_NEW_PROJECTION))
_mesa_update_modelview_project( ctx, new_state );
if (new_state & (_NEW_PROGRAM|_NEW_TEXTURE|_NEW_TEXTURE_MATRIX))
_mesa_update_texture( ctx, new_state );
if (new_state & _NEW_BUFFERS)
_mesa_update_framebuffer(ctx);
if (new_state & (_NEW_SCISSOR | _NEW_BUFFERS | _NEW_VIEWPORT))
_mesa_update_draw_buffer_bounds( ctx );
if (new_state & _NEW_LIGHT)
_mesa_update_lighting( ctx );
if (new_state & (_NEW_LIGHT | _NEW_PROGRAM))
update_twoside( ctx );
if (new_state & (_NEW_STENCIL | _NEW_BUFFERS))
_mesa_update_stencil( ctx );
if (new_state & _NEW_PIXEL)
_mesa_update_pixel( ctx, new_state );
if (new_state & (_NEW_BUFFERS | _NEW_VIEWPORT))
update_viewport_matrix(ctx);
if (new_state & (_NEW_MULTISAMPLE | _NEW_BUFFERS))
update_multisample( ctx );
/* ctx->_NeedEyeCoords is now up to date.
*
* If the truth value of this variable has changed, update for the
* new lighting space and recompute the positions of lights and the
* normal transform.
*
* If the lighting space hasn't changed, may still need to recompute
* light positions & normal transforms for other reasons.
*/
if (new_state & _MESA_NEW_NEED_EYE_COORDS)
_mesa_update_tnl_spaces( ctx, new_state );
if (new_state & prog_flags) {
/* When we generate programs from fixed-function vertex/fragment state
* this call may generate/bind a new program. If so, we need to
* propogate the _NEW_PROGRAM flag to the driver.
*/
new_prog_state |= update_program( ctx );
}
if (ctx->Const.CheckArrayBounds &&
new_state & (_NEW_ARRAY | _NEW_PROGRAM | _NEW_BUFFER_OBJECT)) {
_mesa_update_array_object_max_element(ctx, ctx->Array.ArrayObj);
}
out:
new_prog_state |= update_program_constants(ctx);
/*
* Give the driver a chance to act upon the new_state flags.
* The driver might plug in different span functions, for example.
* Also, this is where the driver can invalidate the state of any
* active modules (such as swrast_setup, swrast, tnl, etc).
*
* Set ctx->NewState to zero to avoid recursion if
* Driver.UpdateState() has to call FLUSH_VERTICES(). (fixed?)
*/
new_state = ctx->NewState | new_prog_state;
ctx->NewState = 0;
printf("call update state\n");
ctx->Driver.UpdateState(ctx, new_state);
}
/* This is the usual entrypoint for state updates:
*/
void
_mesa_update_state( struct gl_context *ctx )
{
_mesa_lock_context_textures(ctx);
_mesa_update_state_locked(ctx);
_mesa_unlock_context_textures(ctx);
}
/**
* Want to figure out which fragment program inputs are actually
* constant/current values from ctx->Current. These should be
* referenced as a tracked state variable rather than a fragment
* program input, to save the overhead of putting a constant value in
* every submitted vertex, transferring it to hardware, interpolating
* it across the triangle, etc...
*
* When there is a VP bound, just use vp->outputs. But when we're
* generating vp from fixed function state, basically want to
* calculate:
*
* vp_out_2_fp_in( vp_in_2_vp_out( varying_inputs ) |
* potential_vp_outputs )
*
* Where potential_vp_outputs is calculated by looking at enabled
* texgen, etc.
*
* The generated fragment program should then only declare inputs that
* may vary or otherwise differ from the ctx->Current values.
* Otherwise, the fp should track them as state values instead.
*/
void
_mesa_set_varying_vp_inputs( struct gl_context *ctx,
GLbitfield64 varying_inputs )
{
if (ctx->varying_vp_inputs != varying_inputs) {
ctx->varying_vp_inputs = varying_inputs;
/* Only the fixed-func generated programs need to use the flag
* and the fixed-func fragment program uses it only if there is also
* a fixed-func vertex program, so this only depends on the latter.
*
* It's okay to check the VP pointer here, because this is called after
* _mesa_update_state in the vbo module. */
if (ctx->VertexProgram._TnlProgram ||
ctx->FragmentProgram._TexEnvProgram) {
ctx->NewState |= _NEW_VARYING_VP_INPUTS;
}
/*printf("%s %x\n", __FUNCTION__, varying_inputs);*/
}
}
/**
* Used by drivers to tell core Mesa that the driver is going to
* install/ use its own vertex program. In particular, this will
* prevent generated fragment programs from using state vars instead
* of ordinary varyings/inputs.
*/
void
_mesa_set_vp_override(struct gl_context *ctx, GLboolean flag)
{
if (ctx->VertexProgram._Overriden != flag) {
ctx->VertexProgram._Overriden = flag;
/* Set one of the bits which will trigger fragment program
* regeneration:
*/
ctx->NewState |= _NEW_PROGRAM;
}
}

View File

@ -1,259 +0,0 @@
/*
* Mesa 3-D graphics library
*
* Copyright (C) 1999-2008 Brian Paul 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 "main/glheader.h"
#include "main/accum.h"
#include "main/condrender.h"
#include "main/format_pack.h"
#include "main/macros.h"
#include "main/imports.h"
#include "main/mtypes.h"
#include "s_context.h"
#include "s_depth.h"
#include "s_stencil.h"
/**
* Clear an rgba color buffer with masking if needed.
*/
static void
clear_rgba_buffer(struct gl_context *ctx, struct gl_renderbuffer *rb,
const GLubyte colorMask[4])
{
const GLint x = ctx->DrawBuffer->_Xmin;
const GLint y = ctx->DrawBuffer->_Ymin;
const GLint height = ctx->DrawBuffer->_Ymax - ctx->DrawBuffer->_Ymin;
const GLint width = ctx->DrawBuffer->_Xmax - ctx->DrawBuffer->_Xmin;
const GLuint pixelSize = _mesa_get_format_bytes(rb->Format);
const GLboolean doMasking = (colorMask[0] == 0 ||
colorMask[1] == 0 ||
colorMask[2] == 0 ||
colorMask[3] == 0);
const GLfloat (*clearColor)[4] =
(const GLfloat (*)[4]) ctx->Color.ClearColor.f;
GLbitfield mapMode = GL_MAP_WRITE_BIT;
GLubyte *map;
GLint rowStride;
GLint i, j;
if (doMasking) {
/* we'll need to read buffer values too */
mapMode |= GL_MAP_READ_BIT;
}
/* map dest buffer */
ctx->Driver.MapRenderbuffer(ctx, rb, x, y, width, height,
mapMode, &map, &rowStride);
if (!map) {
_mesa_error(ctx, GL_OUT_OF_MEMORY, "glClear(color)");
return;
}
/* for 1, 2, 4-byte clearing */
#define SIMPLE_TYPE_CLEAR(TYPE) \
do { \
TYPE pixel, pixelMask; \
_mesa_pack_float_rgba_row(rb->Format, 1, clearColor, &pixel); \
if (doMasking) { \
_mesa_pack_colormask(rb->Format, colorMask, &pixelMask); \
pixel &= pixelMask; \
pixelMask = ~pixelMask; \
} \
for (i = 0; i < height; i++) { \
TYPE *row = (TYPE *) map; \
if (doMasking) { \
for (j = 0; j < width; j++) { \
row[j] = (row[j] & pixelMask) | pixel; \
} \
} \
else { \
for (j = 0; j < width; j++) { \
row[j] = pixel; \
} \
} \
map += rowStride; \
} \
} while (0)
/* for 3, 6, 8, 12, 16-byte clearing */
#define MULTI_WORD_CLEAR(TYPE, N) \
do { \
TYPE pixel[N], pixelMask[N]; \
GLuint k; \
_mesa_pack_float_rgba_row(rb->Format, 1, clearColor, pixel); \
if (doMasking) { \
_mesa_pack_colormask(rb->Format, colorMask, pixelMask); \
for (k = 0; k < N; k++) { \
pixel[k] &= pixelMask[k]; \
pixelMask[k] = ~pixelMask[k]; \
} \
} \
for (i = 0; i < height; i++) { \
TYPE *row = (TYPE *) map; \
if (doMasking) { \
for (j = 0; j < width; j++) { \
for (k = 0; k < N; k++) { \
row[j * N + k] = \
(row[j * N + k] & pixelMask[k]) | pixel[k]; \
} \
} \
} \
else { \
for (j = 0; j < width; j++) { \
for (k = 0; k < N; k++) { \
row[j * N + k] = pixel[k]; \
} \
} \
} \
map += rowStride; \
} \
} while(0)
switch (pixelSize) {
case 1:
SIMPLE_TYPE_CLEAR(GLubyte);
break;
case 2:
SIMPLE_TYPE_CLEAR(GLushort);
break;
case 3:
MULTI_WORD_CLEAR(GLubyte, 3);
break;
case 4:
SIMPLE_TYPE_CLEAR(GLuint);
break;
case 6:
MULTI_WORD_CLEAR(GLushort, 3);
break;
case 8:
MULTI_WORD_CLEAR(GLuint, 2);
break;
case 12:
MULTI_WORD_CLEAR(GLuint, 3);
break;
case 16:
MULTI_WORD_CLEAR(GLuint, 4);
break;
default:
_mesa_problem(ctx, "bad pixel size in clear_rgba_buffer()");
}
/* unmap buffer */
ctx->Driver.UnmapRenderbuffer(ctx, rb);
}
/**
* Clear the front/back/left/right/aux color buffers.
* This function is usually only called if the device driver can't
* clear its own color buffers for some reason (such as with masking).
*/
static void
clear_color_buffers(struct gl_context *ctx)
{
GLuint buf;
for (buf = 0; buf < ctx->DrawBuffer->_NumColorDrawBuffers; buf++) {
struct gl_renderbuffer *rb = ctx->DrawBuffer->_ColorDrawBuffers[buf];
/* If this is an ES2 context or GL_ARB_ES2_compatibility is supported,
* the framebuffer can be complete with some attachments be missing. In
* this case the _ColorDrawBuffers pointer will be NULL.
*/
if (rb == NULL)
continue;
clear_rgba_buffer(ctx, rb, ctx->Color.ColorMask[buf]);
}
}
/**
* Called via the device driver's ctx->Driver.Clear() function if the
* device driver can't clear one or more of the buffers itself.
* \param buffers bitfield of BUFFER_BIT_* values indicating which
* renderbuffers are to be cleared.
* \param all if GL_TRUE, clear whole buffer, else clear specified region.
*/
void
_swrast_Clear(struct gl_context *ctx, GLbitfield buffers)
{
const GLbitfield BUFFER_DS = BUFFER_BIT_DEPTH | BUFFER_BIT_STENCIL;
ENTER();
#ifdef DEBUG_FOO
{
const GLbitfield legalBits =
BUFFER_BIT_FRONT_LEFT |
BUFFER_BIT_FRONT_RIGHT |
BUFFER_BIT_BACK_LEFT |
BUFFER_BIT_BACK_RIGHT |
BUFFER_BIT_DEPTH |
BUFFER_BIT_STENCIL |
BUFFER_BIT_ACCUM |
BUFFER_BIT_AUX0;
assert((buffers & (~legalBits)) == 0);
}
#endif
if (!_mesa_check_conditional_render(ctx))
return; /* don't clear */
if (SWRAST_CONTEXT(ctx)->NewState)
_swrast_validate_derived(ctx);
if ((buffers & BUFFER_BITS_COLOR)
&& (ctx->DrawBuffer->_NumColorDrawBuffers > 0)) {
clear_color_buffers(ctx);
}
if (buffers & BUFFER_BIT_ACCUM) {
_mesa_clear_accum_buffer(ctx);
}
if (buffers & BUFFER_DS) {
struct gl_renderbuffer *depthRb =
ctx->DrawBuffer->Attachment[BUFFER_DEPTH].Renderbuffer;
struct gl_renderbuffer *stencilRb =
ctx->DrawBuffer->Attachment[BUFFER_STENCIL].Renderbuffer;
if ((buffers & BUFFER_DS) == BUFFER_DS && depthRb == stencilRb) {
/* clear depth and stencil together */
_swrast_clear_depth_stencil_buffer(ctx);
}
else {
/* clear depth, stencil separately */
if (buffers & BUFFER_BIT_DEPTH) {
_swrast_clear_depth_buffer(ctx);
}
if (buffers & BUFFER_BIT_STENCIL) {
_swrast_clear_stencil_buffer(ctx);
}
}
}
LEAVE();
}

File diff suppressed because it is too large Load Diff

View File

@ -1,159 +0,0 @@
/*
* This file is automatically generated from the Mesa internal type
* definitions. Do not edit directly.
*/
#ifndef __ASM_TYPES_H__
#define __ASM_TYPES_H__
/* =============================================================
* Offsets for struct gl_context
*/
#define CTX_LIGHT_ENABLED 8776
#define CTX_LIGHT_SHADE_MODEL 8780
#define CTX_LIGHT_COLOR_MAT_FACE 8788
#define CTX_LIGHT_COLOR_MAT_MODE 8792
#define CTX_LIGHT_COLOR_MAT_MASK 8796
#define CTX_LIGHT_COLOR_MAT_ENABLED 8800
#define CTX_LIGHT_ENABLED_LIST 8816
#define CTX_LIGHT_NEED_VERTS 9081
#define CTX_LIGHT_BASE_COLOR 9084
/* =============================================================
* Offsets for struct vertex_buffer
*/
#define VB_SIZE 0
#define VB_COUNT 4
#define VB_ELTS 8
#define VB_OBJ_PTR 112
#define VB_EYE_PTR 16
#define VB_CLIP_PTR 24
#define VB_PROJ_CLIP_PTR 32
#define VB_CLIP_OR_MASK 40
#define VB_CLIP_MASK 48
#define VB_NORMAL_PTR 128
#define VB_EDGE_FLAG 64
#define VB_TEX0_COORD_PTR 176
#define VB_TEX1_COORD_PTR 184
#define VB_TEX2_COORD_PTR 192
#define VB_TEX3_COORD_PTR 200
#define VB_INDEX_PTR 160
#define VB_COLOR_PTR 136
#define VB_SECONDARY_COLOR_PTR 144
#define VB_FOG_COORD_PTR 152
#define VB_PRIMITIVE 96
/*
* Flags for struct vertex_buffer
*/
#define VERT_BIT_OBJ 0x1
#define VERT_BIT_NORM 0x4
#define VERT_BIT_RGBA 0x8
#define VERT_BIT_SPEC_RGB 0x10
#define VERT_BIT_FOG_COORD 0x20
#define VERT_BIT_TEX0 0x100
#define VERT_BIT_TEX1 0x200
#define VERT_BIT_TEX2 0x400
#define VERT_BIT_TEX3 0x800
/* =============================================================
* Offsets for GLvector4f
*/
#define V4F_DATA 0
#define V4F_START 8
#define V4F_COUNT 16
#define V4F_STRIDE 20
#define V4F_SIZE 24
#define V4F_FLAGS 28
/*
* Flags for GLvector4f
*/
#define VEC_MALLOC 0x10
#define VEC_NOT_WRITEABLE 0x40
#define VEC_BAD_STRIDE 0x100
#define VEC_SIZE_1 0x1
#define VEC_SIZE_2 0x3
#define VEC_SIZE_3 0x7
#define VEC_SIZE_4 0xf
/* =============================================================
* Offsets for GLmatrix
*/
#define MATRIX_DATA 0
#define MATRIX_INV 8
#define MATRIX_FLAGS 16
#define MATRIX_TYPE 20
/* =============================================================
* Offsets for struct gl_light
*/
#define LIGHT_NEXT 0
#define LIGHT_PREV 8
#define LIGHT_AMBIENT 16
#define LIGHT_DIFFUSE 32
#define LIGHT_SPECULAR 48
#define LIGHT_EYE_POSITION 64
#define LIGHT_SPOT_DIRECTION 80
#define LIGHT_SPOT_EXPONENT 96
#define LIGHT_SPOT_CUTOFF 100
#define LIGHT_COS_CUTOFF 104
#define LIGHT_CONST_ATTEN 108
#define LIGHT_LINEAR_ATTEN 112
#define LIGHT_QUADRATIC_ATTEN 116
#define LIGHT_ENABLED 120
#define LIGHT_FLAGS 124
#define LIGHT_POSITION 128
#define LIGHT_VP_INF_NORM 144
#define LIGHT_H_INF_NORM 156
#define LIGHT_NORM_DIRECTION 168
#define LIGHT_VP_INF_SPOT_ATTEN 184
#define LIGHT_MAT_AMBIENT 188
#define LIGHT_MAT_DIFFUSE 212
#define LIGHT_MAT_SPECULAR 236
#define SIZEOF_GL_LIGHT 264
/*
* Flags for struct gl_light
*/
#define LIGHT_SPOT 0x1
#define LIGHT_LOCAL_VIEWER 0x2
#define LIGHT_POSITIONAL 0x4
#define LIGHT_NEED_VERTICES 0x6
/* =============================================================
* Offsets for struct gl_lightmodel
*/
#define LIGHT_MODEL_AMBIENT 0
#define LIGHT_MODEL_LOCAL_VIEWER 16
#define LIGHT_MODEL_TWO_SIDE 17
#define LIGHT_MODEL_COLOR_CONTROL 20
#endif /* __ASM_TYPES_H__ */

View File

@ -1,401 +0,0 @@
;
/*
* Written by Jos<EFBFBD> Fonseca <j_r_fonseca@yahoo.co.uk>
*/
#ifdef USE_MMX_ASM
#include "assyntax.h"
#include "matypes.h"
/* integer multiplication - alpha plus one
*
* makes the following approximation to the division (Sree)
*
* rgb*a/255 ~= (rgb*(a+1)) >> 256
*
* which is the fastest method that satisfies the following OpenGL criteria
*
* 0*0 = 0 and 255*255 = 255
*
* note that MX1 is a register with 0xffffffffffffffff constant which can be easily obtained making
*
* PCMPEQW ( MX1, MX1 )
*/
#define GMB_MULT_AP1( MP1, MA1, MP2, MA2, MX1 ) \
PSUBW ( MX1, MA1 ) /* a1 + 1 | a1 + 1 | a1 + 1 | a1 + 1 */ ;\
PMULLW ( MP1, MA1 ) /* t1 = p1*a1 */ ;\
;\
TWO(PSUBW ( MX1, MA2 )) /* a2 + 1 | a2 + 1 | a2 + 1 | a2 + 1 */ ;\
TWO(PMULLW ( MP2, MA2 )) /* t2 = p2*a2 */ ;\
;\
PSRLW ( CONST(8), MA1 ) /* t1 >> 8 ~= t1/255 */ ;\
TWO(PSRLW ( CONST(8), MA2 )) /* t2 >> 8 ~= t2/255 */
/* integer multiplication - geometric series
*
* takes the geometric series approximation to the division
*
* t/255 = (t >> 8) + (t >> 16) + (t >> 24) ..
*
* in this case just the first two terms to fit in 16bit arithmetic
*
* t/255 ~= (t + (t >> 8)) >> 8
*
* note that just by itself it doesn't satisfies the OpenGL criteria, as 255*255 = 254,
* so the special case a = 255 must be accounted or roundoff must be used
*/
#define GMB_MULT_GS( MP1, MA1, MP2, MA2 ) \
PMULLW ( MP1, MA1 ) /* t1 = p1*a1 */ ;\
TWO(PMULLW ( MP2, MA2 )) /* t2 = p2*a2 */ ;\
;\
MOVQ ( MA1, MP1 ) ;\
PSRLW ( CONST(8), MA1 ) /* t1 >> 8 */ ;\
;\
TWO(MOVQ ( MA2, MP2 )) ;\
TWO(PSRLW ( CONST(8), MA2 )) /* t2 >> 8 */ ;\
;\
PADDW ( MP1, MA1 ) /* t1 + (t1 >> 8) ~= (t1/255) << 8 */ ;\
PSRLW ( CONST(8), MA1 ) /* sa1 | sb1 | sg1 | sr1 */ ;\
;\
TWO(PADDW ( MP2, MA2 )) /* t2 + (t2 >> 8) ~= (t2/255) << 8 */ ;\
TWO(PSRLW ( CONST(8), MA2 )) /* sa2 | sb2 | sg2 | sr2 */
/* integer multiplication - geometric series plus rounding
*
* when using a geometric series division instead of truncating the result
* use roundoff in the approximation (Jim Blinn)
*
* t = rgb*a + 0x80
*
* achieving the exact results
*
* note that M80 is register with the 0x0080008000800080 constant
*/
#define GMB_MULT_GSR( MP1, MA1, MP2, MA2, M80 ) \
PMULLW ( MP1, MA1 ) /* t1 = p1*a1 */ ;\
PADDW ( M80, MA1 ) /* t1 += 0x80 */ ;\
;\
TWO(PMULLW ( MP2, MA2 )) /* t2 = p2*a2 */ ;\
TWO(PADDW ( M80, MA2 )) /* t2 += 0x80 */ ;\
;\
MOVQ ( MA1, MP1 ) ;\
PSRLW ( CONST(8), MA1 ) /* t1 >> 8 */ ;\
;\
TWO(MOVQ ( MA2, MP2 )) ;\
TWO(PSRLW ( CONST(8), MA2 )) /* t2 >> 8 */ ;\
;\
PADDW ( MP1, MA1 ) /* t1 + (t1 >> 8) ~= (t1/255) << 8 */ ;\
PSRLW ( CONST(8), MA1 ) /* sa1 | sb1 | sg1 | sr1 */ ;\
;\
TWO(PADDW ( MP2, MA2 )) /* t2 + (t2 >> 8) ~= (t2/255) << 8 */ ;\
TWO(PSRLW ( CONST(8), MA2 )) /* sa2 | sb2 | sg2 | sr2 */
/* linear interpolation - geometric series
*/
#define GMB_LERP_GS( MP1, MQ1, MA1, MP2, MQ2, MA2) \
PSUBW ( MQ1, MP1 ) /* pa1 - qa1 | pb1 - qb1 | pg1 - qg1 | pr1 - qr1 */ ;\
PSLLW ( CONST(8), MQ1 ) /* q1 << 8 */ ;\
PMULLW ( MP1, MA1 ) /* t1 = (q1 - p1)*pa1 */ ;\
;\
TWO(PSUBW ( MQ2, MP2 )) /* pa2 - qa2 | pb2 - qb2 | pg2 - qg2 | pr2 - qr2 */ ;\
TWO(PSLLW ( CONST(8), MQ2 )) /* q2 << 8 */ ;\
TWO(PMULLW ( MP2, MA2 )) /* t2 = (q2 - p2)*pa2 */ ;\
;\
MOVQ ( MA1, MP1 ) ;\
PSRLW ( CONST(8), MA1 ) /* t1 >> 8 */ ;\
;\
TWO(MOVQ ( MA2, MP2 )) ;\
TWO(PSRLW ( CONST(8), MA2 )) /* t2 >> 8 */ ;\
;\
PADDW ( MP1, MA1 ) /* t1 + (t1 >> 8) ~= (t1/255) << 8 */ ;\
TWO(PADDW ( MP2, MA2 )) /* t2 + (t2 >> 8) ~= (t2/255) << 8 */ ;\
;\
PADDW ( MQ1, MA1 ) /* (t1/255 + q1) << 8 */ ;\
TWO(PADDW ( MQ2, MA2 )) /* (t2/255 + q2) << 8 */ ;\
;\
PSRLW ( CONST(8), MA1 ) /* sa1 | sb1 | sg1 | sr1 */ ;\
TWO(PSRLW ( CONST(8), MA2 )) /* sa2 | sb2 | sg2 | sr2 */
/* linear interpolation - geometric series with roundoff
*
* this is a generalization of Blinn's formula to signed arithmetic
*
* note that M80 is a register with the 0x0080008000800080 constant
*/
#define GMB_LERP_GSR( MP1, MQ1, MA1, MP2, MQ2, MA2, M80) \
PSUBW ( MQ1, MP1 ) /* pa1 - qa1 | pb1 - qb1 | pg1 - qg1 | pr1 - qr1 */ ;\
PSLLW ( CONST(8), MQ1 ) /* q1 << 8 */ ;\
PMULLW ( MP1, MA1 ) /* t1 = (q1 - p1)*pa1 */ ;\
;\
TWO(PSUBW ( MQ2, MP2 )) /* pa2 - qa2 | pb2 - qb2 | pg2 - qg2 | pr2 - qr2 */ ;\
TWO(PSLLW ( CONST(8), MQ2 )) /* q2 << 8 */ ;\
TWO(PMULLW ( MP2, MA2 )) /* t2 = (q2 - p2)*pa2 */ ;\
;\
PSRLW ( CONST(15), MP1 ) /* q1 > p1 ? 1 : 0 */ ;\
TWO(PSRLW ( CONST(15), MP2 )) /* q2 > q2 ? 1 : 0 */ ;\
;\
PSLLW ( CONST(8), MP1 ) /* q1 > p1 ? 0x100 : 0 */ ;\
TWO(PSLLW ( CONST(8), MP2 )) /* q2 > q2 ? 0x100 : 0 */ ;\
;\
PSUBW ( MP1, MA1 ) /* t1 -=? 0x100 */ ;\
TWO(PSUBW ( MP2, MA2 )) /* t2 -=? 0x100 */ ;\
;\
PADDW ( M80, MA1 ) /* t1 += 0x80 */ ;\
TWO(PADDW ( M80, MA2 )) /* t2 += 0x80 */ ;\
;\
MOVQ ( MA1, MP1 ) ;\
PSRLW ( CONST(8), MA1 ) /* t1 >> 8 */ ;\
;\
TWO(MOVQ ( MA2, MP2 )) ;\
TWO(PSRLW ( CONST(8), MA2 )) /* t2 >> 8 */ ;\
;\
PADDW ( MP1, MA1 ) /* t1 + (t1 >> 8) ~= (t1/255) << 8 */ ;\
TWO(PADDW ( MP2, MA2 )) /* t2 + (t2 >> 8) ~= (t2/255) << 8 */ ;\
;\
PADDW ( MQ1, MA1 ) /* (t1/255 + q1) << 8 */ ;\
TWO(PADDW ( MQ2, MA2 )) /* (t2/255 + q2) << 8 */ ;\
;\
PSRLW ( CONST(8), MA1 ) /* sa1 | sb1 | sg1 | sr1 */ ;\
TWO(PSRLW ( CONST(8), MA2 )) /* sa2 | sb2 | sg2 | sr2 */
/* linear interpolation - geometric series with correction
*
* instead of the roundoff this adds a small correction to satisfy the OpenGL criteria
*
* t/255 ~= (t + (t >> 8) + (t >> 15)) >> 8
*
* note that although is faster than rounding off it doesn't give always the exact results
*/
#define GMB_LERP_GSC( MP1, MQ1, MA1, MP2, MQ2, MA2) \
PSUBW ( MQ1, MP1 ) /* pa1 - qa1 | pb1 - qb1 | pg1 - qg1 | pr1 - qr1 */ ;\
PSLLW ( CONST(8), MQ1 ) /* q1 << 8 */ ;\
PMULLW ( MP1, MA1 ) /* t1 = (q1 - p1)*pa1 */ ;\
;\
TWO(PSUBW ( MQ2, MP2 )) /* pa2 - qa2 | pb2 - qb2 | pg2 - qg2 | pr2 - qr2 */ ;\
TWO(PSLLW ( CONST(8), MQ2 )) /* q2 << 8 */ ;\
TWO(PMULLW ( MP2, MA2 )) /* t2 = (q2 - p2)*pa2 */ ;\
;\
MOVQ ( MA1, MP1 ) ;\
PSRLW ( CONST(8), MA1 ) /* t1 >> 8 */ ;\
;\
TWO(MOVQ ( MA2, MP2 )) ;\
TWO(PSRLW ( CONST(8), MA2 )) /* t2 >> 8 */ ;\
;\
PADDW ( MA1, MP1 ) /* t1 + (t1 >> 8) ~= (t1/255) << 8 */ ;\
PSRLW ( CONST(7), MA1 ) /* t1 >> 15 */ ;\
;\
TWO(PADDW ( MA2, MP2 )) /* t2 + (t2 >> 8) ~= (t2/255) << 8 */ ;\
TWO(PSRLW ( CONST(7), MA2 )) /* t2 >> 15 */ ;\
;\
PADDW ( MP1, MA1 ) /* t1 + (t1 >> 8) + (t1 >>15) ~= (t1/255) << 8 */ ;\
TWO(PADDW ( MP2, MA2 )) /* t2 + (t2 >> 8) + (t2 >>15) ~= (t2/255) << 8 */ ;\
;\
PADDW ( MQ1, MA1 ) /* (t1/255 + q1) << 8 */ ;\
TWO(PADDW ( MQ2, MA2 )) /* (t2/255 + q2) << 8 */ ;\
;\
PSRLW ( CONST(8), MA1 ) /* sa1 | sb1 | sg1 | sr1 */ ;\
TWO(PSRLW ( CONST(8), MA2 )) /* sa2 | sb2 | sg2 | sr2 */
/* common blending setup code
*
* note that M00 is a register with 0x0000000000000000 constant which can be easily obtained making
*
* PXOR ( M00, M00 )
*/
#define GMB_LOAD(rgba, dest, MPP, MQQ) \
ONE(MOVD ( REGIND(rgba), MPP )) /* | | | | qa1 | qb1 | qg1 | qr1 */ ;\
ONE(MOVD ( REGIND(dest), MQQ )) /* | | | | pa1 | pb1 | pg1 | pr1 */ ;\
;\
TWO(MOVQ ( REGIND(rgba), MPP )) /* qa2 | qb2 | qg2 | qr2 | qa1 | qb1 | qg1 | qr1 */ ;\
TWO(MOVQ ( REGIND(dest), MQQ )) /* pa2 | pb2 | pg2 | pr2 | pa1 | pb1 | pg1 | pr1 */
#define GMB_UNPACK(MP1, MQ1, MP2, MQ2, M00) \
TWO(MOVQ ( MP1, MP2 )) ;\
TWO(MOVQ ( MQ1, MQ2 )) ;\
;\
PUNPCKLBW ( M00, MQ1 ) /* qa1 | qb1 | qg1 | qr1 */ ;\
TWO(PUNPCKHBW ( M00, MQ2 )) /* qa2 | qb2 | qg2 | qr2 */ ;\
PUNPCKLBW ( M00, MP1 ) /* pa1 | pb1 | pg1 | pr1 */ ;\
TWO(PUNPCKHBW ( M00, MP2 )) /* pa2 | pb2 | pg2 | pr2 */
#define GMB_ALPHA(MP1, MA1, MP2, MA2) \
MOVQ ( MP1, MA1 ) ;\
TWO(MOVQ ( MP2, MA2 )) ;\
;\
PUNPCKHWD ( MA1, MA1 ) /* pa1 | pa1 | | */ ;\
TWO(PUNPCKHWD ( MA2, MA2 )) /* pa2 | pa2 | | */ ;\
PUNPCKHDQ ( MA1, MA1 ) /* pa1 | pa1 | pa1 | pa1 */ ;\
TWO(PUNPCKHDQ ( MA2, MA2 )) /* pa2 | pa2 | pa2 | pa2 */
#define GMB_PACK( MS1, MS2 ) \
PACKUSWB ( MS2, MS1 ) /* sa2 | sb2 | sg2 | sr2 | sa1 | sb1 | sg1 | sr1 */ ;\
#define GMB_STORE(rgba, MSS ) \
ONE(MOVD ( MSS, REGIND(rgba) )) /* | | | | sa1 | sb1 | sg1 | sr1 */ ;\
TWO(MOVQ ( MSS, REGIND(rgba) )) /* sa2 | sb2 | sg2 | sr2 | sa1 | sb1 | sg1 | sr1 */
/* Kevin F. Quinn <kevquinn@gentoo.org> 2 July 2006
* Replace data segment constants with text-segment
* constants (via pushl/movq)
SEG_DATA
ALIGNDATA8
const_0080:
D_LONG 0x00800080, 0x00800080
const_80:
D_LONG 0x80808080, 0x80808080
*/
#define const_0080_l 0x00800080
#define const_0080_h 0x00800080
#define const_80_l 0x80808080
#define const_80_h 0x80808080
SEG_TEXT
/* Blend transparency function
*/
#define TAG(x) CONCAT(x,_transparency)
#define LLTAG(x) LLBL2(x,_transparency)
#define INIT \
PXOR ( MM0, MM0 ) /* 0x0000 | 0x0000 | 0x0000 | 0x0000 */
#define MAIN( rgba, dest ) \
GMB_LOAD( rgba, dest, MM1, MM2 ) ;\
GMB_UNPACK( MM1, MM2, MM4, MM5, MM0 ) ;\
GMB_ALPHA( MM1, MM3, MM4, MM6 ) ;\
GMB_LERP_GSC( MM1, MM2, MM3, MM4, MM5, MM6 ) ;\
GMB_PACK( MM3, MM6 ) ;\
GMB_STORE( rgba, MM3 )
#include "mmx_blendtmp.h"
/* Blend add function
*
* FIXME: Add some loop unrolling here...
*/
#define TAG(x) CONCAT(x,_add)
#define LLTAG(x) LLBL2(x,_add)
#define INIT
#define MAIN( rgba, dest ) \
ONE(MOVD ( REGIND(rgba), MM1 )) /* | | | | qa1 | qb1 | qg1 | qr1 */ ;\
ONE(MOVD ( REGIND(dest), MM2 )) /* | | | | pa1 | pb1 | pg1 | pr1 */ ;\
ONE(PADDUSB ( MM2, MM1 )) ;\
ONE(MOVD ( MM1, REGIND(rgba) )) /* | | | | sa1 | sb1 | sg1 | sr1 */ ;\
;\
TWO(MOVQ ( REGIND(rgba), MM1 )) /* qa2 | qb2 | qg2 | qr2 | qa1 | qb1 | qg1 | qr1 */ ;\
TWO(PADDUSB ( REGIND(dest), MM1 )) /* sa2 | sb2 | sg2 | sr2 | sa1 | sb1 | sg1 | sr1 */ ;\
TWO(MOVQ ( MM1, REGIND(rgba) ))
#include "mmx_blendtmp.h"
/* Blend min function
*/
#define TAG(x) CONCAT(x,_min)
#define LLTAG(x) LLBL2(x,_min)
/* Kevin F. Quinn 2nd July 2006
* Replace data segment constants with text-segment instructions
#define INIT \
MOVQ ( CONTENT(const_80), MM7 )
*/
#define INIT \
PUSH_L ( CONST(const_80_h) ) /* 0x80| 0x80| 0x80| 0x80| 0x80| 0x80| 0x80| 0x80*/ ;\
PUSH_L ( CONST(const_80_l) ) ;\
MOVQ ( REGIND(ESP), MM7 ) ;\
ADD_L ( CONST(8), ESP)
#define MAIN( rgba, dest ) \
GMB_LOAD( rgba, dest, MM1, MM2 ) ;\
MOVQ ( MM1, MM3 ) ;\
MOVQ ( MM2, MM4 ) ;\
PXOR ( MM7, MM3 ) /* unsigned -> signed */ ;\
PXOR ( MM7, MM4 ) /* unsigned -> signed */ ;\
PCMPGTB ( MM3, MM4 ) /* q > p ? 0xff : 0x00 */ ;\
PAND ( MM4, MM1 ) /* q > p ? p : 0 */ ;\
PANDN ( MM2, MM4 ) /* q > p ? 0 : q */ ;\
POR ( MM1, MM4 ) /* q > p ? p : q */ ;\
GMB_STORE( rgba, MM4 )
#include "mmx_blendtmp.h"
/* Blend max function
*/
#define TAG(x) CONCAT(x,_max)
#define LLTAG(x) LLBL2(x,_max)
/* Kevin F. Quinn 2nd July 2006
* Replace data segment constants with text-segment instructions
#define INIT \
MOVQ ( CONTENT(const_80), MM7 )
*/
#define INIT \
PUSH_L ( CONST(const_80_l) ) /* 0x80| 0x80| 0x80| 0x80| 0x80| 0x80| 0x80| 0x80*/ ;\
PUSH_L ( CONST(const_80_h) ) ;\
MOVQ ( REGIND(ESP), MM7 ) ;\
ADD_L ( CONST(8), ESP)
#define MAIN( rgba, dest ) \
GMB_LOAD( rgba, dest, MM1, MM2 ) ;\
MOVQ ( MM1, MM3 ) ;\
MOVQ ( MM2, MM4 ) ;\
PXOR ( MM7, MM3 ) /* unsigned -> signed */ ;\
PXOR ( MM7, MM4 ) /* unsigned -> signed */ ;\
PCMPGTB ( MM3, MM4 ) /* q > p ? 0xff : 0x00 */ ;\
PAND ( MM4, MM2 ) /* q > p ? q : 0 */ ;\
PANDN ( MM1, MM4 ) /* q > p ? 0 : p */ ;\
POR ( MM2, MM4 ) /* q > p ? p : q */ ;\
GMB_STORE( rgba, MM4 )
#include "mmx_blendtmp.h"
/* Blend modulate function
*/
#define TAG(x) CONCAT(x,_modulate)
#define LLTAG(x) LLBL2(x,_modulate)
/* Kevin F. Quinn 2nd July 2006
* Replace data segment constants with text-segment instructions
#define INIT \
MOVQ ( CONTENT(const_0080), MM7 )
*/
#define INIT \
PXOR ( MM0, MM0 ) /* 0x0000 | 0x0000 | 0x0000 | 0x0000 */ ;\
PUSH_L ( CONST(const_0080_l) ) /* 0x0080 | 0x0080 | 0x0080 | 0x0080 */ ;\
PUSH_L ( CONST(const_0080_h) ) ;\
MOVQ ( REGIND(ESP), MM7 ) ;\
ADD_L ( CONST(8), ESP)
#define MAIN( rgba, dest ) \
GMB_LOAD( rgba, dest, MM1, MM2 ) ;\
GMB_UNPACK( MM1, MM2, MM4, MM5, MM0 ) ;\
GMB_MULT_GSR( MM1, MM2, MM4, MM5, MM7 ) ;\
GMB_PACK( MM2, MM5 ) ;\
GMB_STORE( rgba, MM2 )
#include "mmx_blendtmp.h"
#endif
#if defined (__ELF__) && defined (__linux__)
.section .note.GNU-stack,"",%progbits
#endif