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