forked from KolibriOS/kolibrios
mesa: cleanup
git-svn-id: svn://kolibrios.org@4360 a494cfbc-eb01-0410-851d-a64ba20cac60
This commit is contained in:
parent
ab3eee4bd8
commit
4fdea57f1b
File diff suppressed because it is too large
Load Diff
@ -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
@ -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;
|
||||
}
|
@ -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;
|
||||
}
|
@ -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;
|
||||
}
|
@ -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);
|
||||
}
|
@ -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
|
@ -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 */
|
@ -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;
|
||||
}
|
@ -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 */
|
@ -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,
|
||||
};
|
@ -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
@ -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);
|
||||
}
|
||||
}
|
@ -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(®ion);
|
||||
}
|
@ -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;
|
||||
}
|
@ -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
@ -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;
|
||||
}
|
@ -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;
|
||||
}
|
||||
}
|
@ -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
@ -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__ */
|
@ -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
|
Loading…
Reference in New Issue
Block a user