diff options
25 files changed, 7294 insertions, 7216 deletions
diff --git a/mesalib/src/glsl/ast_to_hir.cpp b/mesalib/src/glsl/ast_to_hir.cpp index 9538aa62b..a11bfbab8 100644 --- a/mesalib/src/glsl/ast_to_hir.cpp +++ b/mesalib/src/glsl/ast_to_hir.cpp @@ -848,6 +848,36 @@ do_comparison(void *mem_ctx, int operation, ir_rvalue *op0, ir_rvalue *op1) return cmp; } +/* For logical operations, we want to ensure that the operands are + * scalar booleans. If it isn't, emit an error and return a constant + * boolean to avoid triggering cascading error messages. + */ +ir_rvalue * +get_scalar_boolean_operand(exec_list *instructions, + struct _mesa_glsl_parse_state *state, + ast_expression *parent_expr, + int operand, + const char *operand_name, + bool *error_emitted) +{ + ast_expression *expr = parent_expr->subexpressions[operand]; + void *ctx = state; + ir_rvalue *val = expr->hir(instructions, state); + + if (val->type->is_boolean() && val->type->is_scalar()) + return val; + + if (!*error_emitted) { + YYLTYPE loc = expr->get_location(); + _mesa_glsl_error(&loc, state, "%s of `%s' must be scalar boolean", + operand_name, + parent_expr->operator_string(parent_expr->oper)); + *error_emitted = true; + } + + return new(ctx) ir_constant(true); +} + ir_rvalue * ast_expression::hir(exec_list *instructions, struct _mesa_glsl_parse_state *state) @@ -1043,10 +1073,14 @@ ast_expression::hir(exec_list *instructions, error_emitted = true; } - result = do_comparison(ctx, operations[this->oper], op[0], op[1]); - type = glsl_type::bool_type; + if (error_emitted) { + result = new(ctx) ir_constant(false); + } else { + result = do_comparison(ctx, operations[this->oper], op[0], op[1]); + assert(result->type == glsl_type::bool_type); + type = glsl_type::bool_type; + } - assert(error_emitted || (result->type == glsl_type::bool_type)); break; case ast_bit_and: @@ -1079,29 +1113,16 @@ ast_expression::hir(exec_list *instructions, break; case ast_logic_and: { - op[0] = this->subexpressions[0]->hir(instructions, state); - - if (!op[0]->type->is_boolean() || !op[0]->type->is_scalar()) { - YYLTYPE loc = this->subexpressions[0]->get_location(); - - _mesa_glsl_error(& loc, state, "LHS of `%s' must be scalar boolean", - operator_string(this->oper)); - error_emitted = true; - } + exec_list rhs_instructions; + op[0] = get_scalar_boolean_operand(instructions, state, this, 0, + "LHS", &error_emitted); + op[1] = get_scalar_boolean_operand(&rhs_instructions, state, this, 1, + "RHS", &error_emitted); ir_constant *op0_const = op[0]->constant_expression_value(); if (op0_const) { if (op0_const->value.b[0]) { - op[1] = this->subexpressions[1]->hir(instructions, state); - - if (!op[1]->type->is_boolean() || !op[1]->type->is_scalar()) { - YYLTYPE loc = this->subexpressions[1]->get_location(); - - _mesa_glsl_error(& loc, state, - "RHS of `%s' must be scalar boolean", - operator_string(this->oper)); - error_emitted = true; - } + instructions->append_list(&rhs_instructions); result = op[1]; } else { result = op0_const; @@ -1116,17 +1137,7 @@ ast_expression::hir(exec_list *instructions, ir_if *const stmt = new(ctx) ir_if(op[0]); instructions->push_tail(stmt); - op[1] = this->subexpressions[1]->hir(&stmt->then_instructions, state); - - if (!op[1]->type->is_boolean() || !op[1]->type->is_scalar()) { - YYLTYPE loc = this->subexpressions[1]->get_location(); - - _mesa_glsl_error(& loc, state, - "RHS of `%s' must be scalar boolean", - operator_string(this->oper)); - error_emitted = true; - } - + stmt->then_instructions.append_list(&rhs_instructions); ir_dereference *const then_deref = new(ctx) ir_dereference_variable(tmp); ir_assignment *const then_assign = new(ctx) ir_assignment(then_deref, op[1], NULL); @@ -1144,31 +1155,17 @@ ast_expression::hir(exec_list *instructions, } case ast_logic_or: { - op[0] = this->subexpressions[0]->hir(instructions, state); - - if (!op[0]->type->is_boolean() || !op[0]->type->is_scalar()) { - YYLTYPE loc = this->subexpressions[0]->get_location(); - - _mesa_glsl_error(& loc, state, "LHS of `%s' must be scalar boolean", - operator_string(this->oper)); - error_emitted = true; - } + exec_list rhs_instructions; + op[0] = get_scalar_boolean_operand(instructions, state, this, 0, + "LHS", &error_emitted); + op[1] = get_scalar_boolean_operand(&rhs_instructions, state, this, 1, + "RHS", &error_emitted); ir_constant *op0_const = op[0]->constant_expression_value(); if (op0_const) { if (op0_const->value.b[0]) { result = op0_const; } else { - op[1] = this->subexpressions[1]->hir(instructions, state); - - if (!op[1]->type->is_boolean() || !op[1]->type->is_scalar()) { - YYLTYPE loc = this->subexpressions[1]->get_location(); - - _mesa_glsl_error(& loc, state, - "RHS of `%s' must be scalar boolean", - operator_string(this->oper)); - error_emitted = true; - } result = op[1]; } type = glsl_type::bool_type; @@ -1181,21 +1178,12 @@ ast_expression::hir(exec_list *instructions, ir_if *const stmt = new(ctx) ir_if(op[0]); instructions->push_tail(stmt); - op[1] = this->subexpressions[1]->hir(&stmt->else_instructions, state); - - if (!op[1]->type->is_boolean() || !op[1]->type->is_scalar()) { - YYLTYPE loc = this->subexpressions[1]->get_location(); - - _mesa_glsl_error(& loc, state, "RHS of `%s' must be scalar boolean", - operator_string(this->oper)); - error_emitted = true; - } - ir_dereference *const then_deref = new(ctx) ir_dereference_variable(tmp); ir_assignment *const then_assign = new(ctx) ir_assignment(then_deref, new(ctx) ir_constant(true), NULL); stmt->then_instructions.push_tail(then_assign); + stmt->else_instructions.append_list(&rhs_instructions); ir_dereference *const else_deref = new(ctx) ir_dereference_variable(tmp); ir_assignment *const else_assign = new(ctx) ir_assignment(else_deref, op[1], NULL); @@ -1208,9 +1196,16 @@ ast_expression::hir(exec_list *instructions, } case ast_logic_xor: - op[0] = this->subexpressions[0]->hir(instructions, state); - op[1] = this->subexpressions[1]->hir(instructions, state); - + /* From page 33 (page 39 of the PDF) of the GLSL 1.10 spec: + * + * "The logical binary operators and (&&), or ( | | ), and + * exclusive or (^^). They operate only on two Boolean + * expressions and result in a Boolean expression." + */ + op[0] = get_scalar_boolean_operand(instructions, state, this, 0, "LHS", + &error_emitted); + op[1] = get_scalar_boolean_operand(instructions, state, this, 1, "RHS", + &error_emitted); result = new(ctx) ir_expression(operations[this->oper], glsl_type::bool_type, op[0], op[1]); @@ -1218,15 +1213,8 @@ ast_expression::hir(exec_list *instructions, break; case ast_logic_not: - op[0] = this->subexpressions[0]->hir(instructions, state); - - if (!op[0]->type->is_boolean() || !op[0]->type->is_scalar()) { - YYLTYPE loc = this->subexpressions[0]->get_location(); - - _mesa_glsl_error(& loc, state, - "operand of `!' must be scalar boolean"); - error_emitted = true; - } + op[0] = get_scalar_boolean_operand(instructions, state, this, 0, + "operand", &error_emitted); result = new(ctx) ir_expression(operations[this->oper], glsl_type::bool_type, op[0], NULL); @@ -1313,20 +1301,14 @@ ast_expression::hir(exec_list *instructions, } case ast_conditional: { - op[0] = this->subexpressions[0]->hir(instructions, state); - /* From page 59 (page 65 of the PDF) of the GLSL 1.50 spec: * * "The ternary selection operator (?:). It operates on three * expressions (exp1 ? exp2 : exp3). This operator evaluates the * first expression, which must result in a scalar Boolean." */ - if (!op[0]->type->is_boolean() || !op[0]->type->is_scalar()) { - YYLTYPE loc = this->subexpressions[0]->get_location(); - - _mesa_glsl_error(& loc, state, "?: condition must be scalar boolean"); - error_emitted = true; - } + op[0] = get_scalar_boolean_operand(instructions, state, this, 0, + "condition", &error_emitted); /* The :? operator is implemented by generating an anonymous temporary * followed by an if-statement. The last instruction in each branch of diff --git a/mesalib/src/glsl/glsl_parser_extras.cpp b/mesalib/src/glsl/glsl_parser_extras.cpp index e8881e4d6..5bb3a6f25 100644 --- a/mesalib/src/glsl/glsl_parser_extras.cpp +++ b/mesalib/src/glsl/glsl_parser_extras.cpp @@ -768,7 +768,7 @@ do_common_optimization(exec_list *ir, bool linked, unsigned max_unroll_iteration progress = do_if_simplification(ir) || progress; progress = do_discard_simplification(ir) || progress; progress = do_copy_propagation(ir) || progress; - /*progress = do_copy_propagation_elements(ir) || progress;*/ + progress = do_copy_propagation_elements(ir) || progress; if (linked) progress = do_dead_code(ir) || progress; else diff --git a/mesalib/src/glsl/opt_copy_propagation_elements.cpp b/mesalib/src/glsl/opt_copy_propagation_elements.cpp index 8541d9a8e..a91e624cb 100644 --- a/mesalib/src/glsl/opt_copy_propagation_elements.cpp +++ b/mesalib/src/glsl/opt_copy_propagation_elements.cpp @@ -161,9 +161,16 @@ ir_visitor_status ir_copy_propagation_elements_visitor::visit_leave(ir_assignment *ir) { ir_dereference_variable *lhs = ir->lhs->as_dereference_variable(); + ir_variable *var = ir->lhs->variable_referenced(); + + if (var->type->is_scalar() || var->type->is_vector()) { + kill_entry *k; + + if (lhs) + k = new(mem_ctx) kill_entry(var, ir->write_mask); + else + k = new(mem_ctx) kill_entry(var, ~0); - if (lhs && (lhs->type->is_scalar() || lhs->type->is_vector())) { - kill_entry *k = new(mem_ctx) kill_entry(lhs->var, ir->write_mask); kill(k); } @@ -383,8 +390,10 @@ ir_copy_propagation_elements_visitor::kill(kill_entry *k) if (entry->lhs == k->var) { entry->write_mask = entry->write_mask & ~k->write_mask; - if (entry->write_mask == 0) + if (entry->write_mask == 0) { entry->remove(); + continue; + } } if (entry->rhs == k->var) { entry->remove(); diff --git a/mesalib/src/mesa/main/context.c b/mesalib/src/mesa/main/context.c index 4f6712a10..8053edc23 100644 --- a/mesalib/src/mesa/main/context.c +++ b/mesalib/src/mesa/main/context.c @@ -1,1886 +1,1888 @@ -/*
- * Mesa 3-D graphics library
- * Version: 7.3
- *
- * Copyright (C) 1999-2007 Brian Paul All Rights Reserved.
- * Copyright (C) 2008 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
- * BRIAN PAUL 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 context.c
- * Mesa context/visual/framebuffer management functions.
- * \author Brian Paul
- */
-
-/**
- * \mainpage Mesa Main Module
- *
- * \section MainIntroduction Introduction
- *
- * The Mesa Main module consists of all the files in the main/ directory.
- * Among the features of this module are:
- * <UL>
- * <LI> Structures to represent most GL state </LI>
- * <LI> State set/get functions </LI>
- * <LI> Display lists </LI>
- * <LI> Texture unit, object and image handling </LI>
- * <LI> Matrix and attribute stacks </LI>
- * </UL>
- *
- * Other modules are responsible for API dispatch, vertex transformation,
- * point/line/triangle setup, rasterization, vertex array caching,
- * vertex/fragment programs/shaders, etc.
- *
- *
- * \section AboutDoxygen About Doxygen
- *
- * If you're viewing this information as Doxygen-generated HTML you'll
- * see the documentation index at the top of this page.
- *
- * The first line lists the Mesa source code modules.
- * The second line lists the indexes available for viewing the documentation
- * for each module.
- *
- * Selecting the <b>Main page</b> link will display a summary of the module
- * (this page).
- *
- * Selecting <b>Data Structures</b> will list all C structures.
- *
- * Selecting the <b>File List</b> link will list all the source files in
- * the module.
- * Selecting a filename will show a list of all functions defined in that file.
- *
- * Selecting the <b>Data Fields</b> link will display a list of all
- * documented structure members.
- *
- * Selecting the <b>Globals</b> link will display a list
- * of all functions, structures, global variables and macros in the module.
- *
- */
-
-
-#include "glheader.h"
-#include "mfeatures.h"
-#include "imports.h"
-#include "accum.h"
-#include "api_exec.h"
-#include "arrayobj.h"
-#include "attrib.h"
-#include "blend.h"
-#include "buffers.h"
-#include "bufferobj.h"
-#include "context.h"
-#include "cpuinfo.h"
-#include "debug.h"
-#include "depth.h"
-#include "dlist.h"
-#include "eval.h"
-#include "extensions.h"
-#include "fbobject.h"
-#include "feedback.h"
-#include "fog.h"
-#include "formats.h"
-#include "framebuffer.h"
-#include "hint.h"
-#include "hash.h"
-#include "light.h"
-#include "lines.h"
-#include "macros.h"
-#include "matrix.h"
-#include "multisample.h"
-#include "pixel.h"
-#include "pixelstore.h"
-#include "points.h"
-#include "polygon.h"
-#include "queryobj.h"
-#include "syncobj.h"
-#include "rastpos.h"
-#include "remap.h"
-#include "scissor.h"
-#include "shared.h"
-#include "shaderobj.h"
-#include "simple_list.h"
-#include "state.h"
-#include "stencil.h"
-#include "texcompress_s3tc.h"
-#include "texstate.h"
-#include "transformfeedback.h"
-#include "mtypes.h"
-#include "varray.h"
-#include "version.h"
-#include "viewport.h"
-#include "vtxfmt.h"
-#include "program/program.h"
-#include "program/prog_print.h"
-#if _HAVE_FULL_GL
-#include "math/m_matrix.h"
-#endif
-#include "main/dispatch.h" /* for _gloffset_COUNT */
-
-#ifdef USE_SPARC_ASM
-#include "sparc/sparc.h"
-#endif
-
-#include "glsl_parser_extras.h"
-#include <stdbool.h>
-
-
-#ifndef MESA_VERBOSE
-int MESA_VERBOSE = 0;
-#endif
-
-#ifndef MESA_DEBUG_FLAGS
-int MESA_DEBUG_FLAGS = 0;
-#endif
-
-
-/* ubyte -> float conversion */
-GLfloat _mesa_ubyte_to_float_color_tab[256];
-
-
-
-/**
- * Swap buffers notification callback.
- *
- * \param ctx GL context.
- *
- * Called by window system just before swapping buffers.
- * We have to finish any pending rendering.
- */
-void
-_mesa_notifySwapBuffers(struct gl_context *ctx)
-{
- if (MESA_VERBOSE & VERBOSE_SWAPBUFFERS)
- _mesa_debug(ctx, "SwapBuffers\n");
- FLUSH_CURRENT( ctx, 0 );
- if (ctx->Driver.Flush) {
- ctx->Driver.Flush(ctx);
- }
-}
-
-
-/**********************************************************************/
-/** \name GL Visual allocation/destruction */
-/**********************************************************************/
-/*@{*/
-
-/**
- * Allocates a struct gl_config structure and initializes it via
- * _mesa_initialize_visual().
- *
- * \param dbFlag double buffering
- * \param stereoFlag stereo buffer
- * \param depthBits requested bits per depth buffer value. Any value in [0, 32]
- * is acceptable but the actual depth type will be GLushort or GLuint as
- * needed.
- * \param stencilBits requested minimum bits per stencil buffer value
- * \param accumRedBits, accumGreenBits, accumBlueBits, accumAlphaBits number of bits per color component in accum buffer.
- * \param indexBits number of bits per pixel if \p rgbFlag is GL_FALSE
- * \param redBits number of bits per color component in frame buffer for RGB(A)
- * mode. We always use 8 in core Mesa though.
- * \param greenBits same as above.
- * \param blueBits same as above.
- * \param alphaBits same as above.
- * \param numSamples not really used.
- *
- * \return pointer to new struct gl_config or NULL if requested parameters can't be
- * met.
- *
- * \note Need to add params for level and numAuxBuffers (at least)
- */
-struct gl_config *
-_mesa_create_visual( GLboolean dbFlag,
- GLboolean stereoFlag,
- GLint redBits,
- GLint greenBits,
- GLint blueBits,
- GLint alphaBits,
- GLint depthBits,
- GLint stencilBits,
- GLint accumRedBits,
- GLint accumGreenBits,
- GLint accumBlueBits,
- GLint accumAlphaBits,
- GLint numSamples )
-{
- struct gl_config *vis = CALLOC_STRUCT(gl_config);
- if (vis) {
- if (!_mesa_initialize_visual(vis, dbFlag, stereoFlag,
- redBits, greenBits, blueBits, alphaBits,
- depthBits, stencilBits,
- accumRedBits, accumGreenBits,
- accumBlueBits, accumAlphaBits,
- numSamples)) {
- free(vis);
- return NULL;
- }
- }
- return vis;
-}
-
-
-/**
- * Makes some sanity checks and fills in the fields of the struct
- * gl_config object with the given parameters. If the caller needs to
- * set additional fields, he should just probably init the whole
- * gl_config object himself.
- *
- * \return GL_TRUE on success, or GL_FALSE on failure.
- *
- * \sa _mesa_create_visual() above for the parameter description.
- */
-GLboolean
-_mesa_initialize_visual( struct gl_config *vis,
- GLboolean dbFlag,
- GLboolean stereoFlag,
- GLint redBits,
- GLint greenBits,
- GLint blueBits,
- GLint alphaBits,
- GLint depthBits,
- GLint stencilBits,
- GLint accumRedBits,
- GLint accumGreenBits,
- GLint accumBlueBits,
- GLint accumAlphaBits,
- GLint numSamples )
-{
- assert(vis);
-
- if (depthBits < 0 || depthBits > 32) {
- return GL_FALSE;
- }
- if (stencilBits < 0 || stencilBits > STENCIL_BITS) {
- return GL_FALSE;
- }
- assert(accumRedBits >= 0);
- assert(accumGreenBits >= 0);
- assert(accumBlueBits >= 0);
- assert(accumAlphaBits >= 0);
-
- vis->rgbMode = GL_TRUE;
- vis->doubleBufferMode = dbFlag;
- vis->stereoMode = stereoFlag;
-
- vis->redBits = redBits;
- vis->greenBits = greenBits;
- vis->blueBits = blueBits;
- vis->alphaBits = alphaBits;
- vis->rgbBits = redBits + greenBits + blueBits;
-
- vis->indexBits = 0;
- vis->depthBits = depthBits;
- vis->stencilBits = stencilBits;
-
- vis->accumRedBits = accumRedBits;
- vis->accumGreenBits = accumGreenBits;
- vis->accumBlueBits = accumBlueBits;
- vis->accumAlphaBits = accumAlphaBits;
-
- vis->haveAccumBuffer = accumRedBits > 0;
- vis->haveDepthBuffer = depthBits > 0;
- vis->haveStencilBuffer = stencilBits > 0;
-
- vis->numAuxBuffers = 0;
- vis->level = 0;
- vis->sampleBuffers = numSamples > 0 ? 1 : 0;
- vis->samples = numSamples;
-
- return GL_TRUE;
-}
-
-
-/**
- * Destroy a visual and free its memory.
- *
- * \param vis visual.
- *
- * Frees the visual structure.
- */
-void
-_mesa_destroy_visual( struct gl_config *vis )
-{
- free(vis);
-}
-
-/*@}*/
-
-
-/**********************************************************************/
-/** \name Context allocation, initialization, destroying
- *
- * The purpose of the most initialization functions here is to provide the
- * default state values according to the OpenGL specification.
- */
-/**********************************************************************/
-/*@{*/
-
-
-/**
- * This is lame. gdb only seems to recognize enum types that are
- * actually used somewhere. We want to be able to print/use enum
- * values such as TEXTURE_2D_INDEX in gdb. But we don't actually use
- * the gl_texture_index type anywhere. Thus, this lame function.
- */
-static void
-dummy_enum_func(void)
-{
- gl_buffer_index bi = BUFFER_FRONT_LEFT;
- gl_face_index fi = FACE_POS_X;
- gl_frag_attrib fa = FRAG_ATTRIB_WPOS;
- gl_frag_result fr = FRAG_RESULT_DEPTH;
- gl_texture_index ti = TEXTURE_2D_ARRAY_INDEX;
- gl_vert_attrib va = VERT_ATTRIB_POS;
- gl_vert_result vr = VERT_RESULT_HPOS;
- gl_geom_attrib ga = GEOM_ATTRIB_POSITION;
- gl_geom_result gr = GEOM_RESULT_POS;
-
- (void) bi;
- (void) fi;
- (void) fa;
- (void) fr;
- (void) ti;
- (void) va;
- (void) vr;
- (void) ga;
- (void) gr;
-}
-
-
-/**
- * One-time initialization mutex lock.
- *
- * \sa Used by one_time_init().
- */
-_glthread_DECLARE_STATIC_MUTEX(OneTimeLock);
-
-
-
-/**
- * Calls all the various one-time-init functions in Mesa.
- *
- * While holding a global mutex lock, calls several initialization functions,
- * and sets the glapi callbacks if the \c MESA_DEBUG environment variable is
- * defined.
- *
- * \sa _math_init().
- */
-static void
-one_time_init( struct gl_context *ctx )
-{
- static GLbitfield api_init_mask = 0x0;
-
- _glthread_LOCK_MUTEX(OneTimeLock);
-
- /* truly one-time init */
- if (!api_init_mask) {
- GLuint i;
-
- /* do some implementation tests */
- assert( sizeof(GLbyte) == 1 );
- assert( sizeof(GLubyte) == 1 );
- assert( sizeof(GLshort) == 2 );
- assert( sizeof(GLushort) == 2 );
- assert( sizeof(GLint) == 4 );
- assert( sizeof(GLuint) == 4 );
-
- _mesa_get_cpu_features();
-
- _mesa_init_sqrt_table();
-
- /* context dependence is never a one-time thing... */
- _mesa_init_get_hash(ctx);
-
- for (i = 0; i < 256; i++) {
- _mesa_ubyte_to_float_color_tab[i] = (float) i / 255.0F;
- }
-
-#if defined(DEBUG) && defined(__DATE__) && defined(__TIME__)
- if (MESA_VERBOSE != 0) {
- _mesa_debug(ctx, "Mesa %s DEBUG build %s %s\n",
- MESA_VERSION_STRING, __DATE__, __TIME__);
- }
-#endif
-
-#ifdef DEBUG
- _mesa_test_formats();
-#endif
- }
-
- /* per-API one-time init */
- if (!(api_init_mask & (1 << ctx->API))) {
- /*
- * This is fine as ES does not use the remap table, but it may not be
- * future-proof. We cannot always initialize the remap table because
- * when an app is linked to libGLES*, there are not enough dynamic
- * entries.
- */
- if (ctx->API == API_OPENGL)
- _mesa_init_remap_table();
- }
-
- api_init_mask |= 1 << ctx->API;
-
- _glthread_UNLOCK_MUTEX(OneTimeLock);
-
- /* Hopefully atexit() is widely available. If not, we may need some
- * #ifdef tests here.
- */
- atexit(_mesa_destroy_shader_compiler);
-
- dummy_enum_func();
-}
-
-
-/**
- * Initialize fields of gl_current_attrib (aka ctx->Current.*)
- */
-static void
-_mesa_init_current(struct gl_context *ctx)
-{
- GLuint i;
-
- /* Init all to (0,0,0,1) */
- for (i = 0; i < Elements(ctx->Current.Attrib); i++) {
- ASSIGN_4V( ctx->Current.Attrib[i], 0.0, 0.0, 0.0, 1.0 );
- }
-
- /* redo special cases: */
- ASSIGN_4V( ctx->Current.Attrib[VERT_ATTRIB_WEIGHT], 1.0, 0.0, 0.0, 0.0 );
- ASSIGN_4V( ctx->Current.Attrib[VERT_ATTRIB_NORMAL], 0.0, 0.0, 1.0, 1.0 );
- ASSIGN_4V( ctx->Current.Attrib[VERT_ATTRIB_COLOR0], 1.0, 1.0, 1.0, 1.0 );
- ASSIGN_4V( ctx->Current.Attrib[VERT_ATTRIB_COLOR1], 0.0, 0.0, 0.0, 1.0 );
- ASSIGN_4V( ctx->Current.Attrib[VERT_ATTRIB_COLOR_INDEX], 1.0, 0.0, 0.0, 1.0 );
- ASSIGN_4V( ctx->Current.Attrib[VERT_ATTRIB_EDGEFLAG], 1.0, 0.0, 0.0, 1.0 );
-}
-
-
-/**
- * Init vertex/fragment/geometry program limits.
- * Important: drivers should override these with actual limits.
- */
-static void
-init_program_limits(GLenum type, struct gl_program_constants *prog)
-{
- prog->MaxInstructions = MAX_PROGRAM_INSTRUCTIONS;
- prog->MaxAluInstructions = MAX_PROGRAM_INSTRUCTIONS;
- prog->MaxTexInstructions = MAX_PROGRAM_INSTRUCTIONS;
- prog->MaxTexIndirections = MAX_PROGRAM_INSTRUCTIONS;
- prog->MaxTemps = MAX_PROGRAM_TEMPS;
- prog->MaxEnvParams = MAX_PROGRAM_ENV_PARAMS;
- prog->MaxLocalParams = MAX_PROGRAM_LOCAL_PARAMS;
- prog->MaxAddressOffset = MAX_PROGRAM_LOCAL_PARAMS;
-
- switch (type) {
- case GL_VERTEX_PROGRAM_ARB:
- prog->MaxParameters = MAX_VERTEX_PROGRAM_PARAMS;
- prog->MaxAttribs = MAX_NV_VERTEX_PROGRAM_INPUTS;
- prog->MaxAddressRegs = MAX_VERTEX_PROGRAM_ADDRESS_REGS;
- prog->MaxUniformComponents = 4 * MAX_UNIFORMS;
- break;
- case GL_FRAGMENT_PROGRAM_ARB:
- prog->MaxParameters = MAX_NV_FRAGMENT_PROGRAM_PARAMS;
- prog->MaxAttribs = MAX_NV_FRAGMENT_PROGRAM_INPUTS;
- prog->MaxAddressRegs = MAX_FRAGMENT_PROGRAM_ADDRESS_REGS;
- prog->MaxUniformComponents = 4 * MAX_UNIFORMS;
- break;
- case MESA_GEOMETRY_PROGRAM:
- prog->MaxParameters = MAX_NV_VERTEX_PROGRAM_PARAMS;
- prog->MaxAttribs = MAX_NV_VERTEX_PROGRAM_INPUTS;
- prog->MaxAddressRegs = MAX_VERTEX_PROGRAM_ADDRESS_REGS;
- prog->MaxUniformComponents = MAX_GEOMETRY_UNIFORM_COMPONENTS;
- break;
- default:
- assert(0 && "Bad program type in init_program_limits()");
- }
-
- /* Set the native limits to zero. This implies that there is no native
- * support for shaders. Let the drivers fill in the actual values.
- */
- prog->MaxNativeInstructions = 0;
- prog->MaxNativeAluInstructions = 0;
- prog->MaxNativeTexInstructions = 0;
- prog->MaxNativeTexIndirections = 0;
- prog->MaxNativeAttribs = 0;
- prog->MaxNativeTemps = 0;
- prog->MaxNativeAddressRegs = 0;
- prog->MaxNativeParameters = 0;
-
- /* Set GLSL datatype range/precision info assuming IEEE float values.
- * Drivers should override these defaults as needed.
- */
- prog->MediumFloat.RangeMin = 127;
- prog->MediumFloat.RangeMax = 127;
- prog->MediumFloat.Precision = 23;
- prog->LowFloat = prog->HighFloat = prog->MediumFloat;
-
- /* Assume ints are stored as floats for now, since this is the least-common
- * denominator. The OpenGL ES spec implies (page 132) that the precision
- * of integer types should be 0. Practically speaking, IEEE
- * single-precision floating point values can only store integers in the
- * range [-0x01000000, 0x01000000] without loss of precision.
- */
- prog->MediumInt.RangeMin = 24;
- prog->MediumInt.RangeMax = 24;
- prog->MediumInt.Precision = 0;
- prog->LowInt = prog->HighInt = prog->MediumInt;
-}
-
-
-/**
- * Initialize fields of gl_constants (aka ctx->Const.*).
- * Use defaults from config.h. The device drivers will often override
- * some of these values (such as number of texture units).
- */
-static void
-_mesa_init_constants(struct gl_context *ctx)
-{
- assert(ctx);
-
- /* Constants, may be overriden (usually only reduced) by device drivers */
- ctx->Const.MaxTextureMbytes = MAX_TEXTURE_MBYTES;
- ctx->Const.MaxTextureLevels = MAX_TEXTURE_LEVELS;
- ctx->Const.Max3DTextureLevels = MAX_3D_TEXTURE_LEVELS;
- ctx->Const.MaxCubeTextureLevels = MAX_CUBE_TEXTURE_LEVELS;
- ctx->Const.MaxTextureRectSize = MAX_TEXTURE_RECT_SIZE;
- ctx->Const.MaxArrayTextureLayers = MAX_ARRAY_TEXTURE_LAYERS;
- ctx->Const.MaxTextureCoordUnits = MAX_TEXTURE_COORD_UNITS;
- ctx->Const.MaxTextureImageUnits = MAX_TEXTURE_IMAGE_UNITS;
- ctx->Const.MaxTextureUnits = MIN2(ctx->Const.MaxTextureCoordUnits,
- ctx->Const.MaxTextureImageUnits);
- ctx->Const.MaxTextureMaxAnisotropy = MAX_TEXTURE_MAX_ANISOTROPY;
- ctx->Const.MaxTextureLodBias = MAX_TEXTURE_LOD_BIAS;
- ctx->Const.MaxTextureBufferSize = 65536;
- ctx->Const.MaxArrayLockSize = MAX_ARRAY_LOCK_SIZE;
- ctx->Const.SubPixelBits = SUB_PIXEL_BITS;
- ctx->Const.MinPointSize = MIN_POINT_SIZE;
- ctx->Const.MaxPointSize = MAX_POINT_SIZE;
- ctx->Const.MinPointSizeAA = MIN_POINT_SIZE;
- ctx->Const.MaxPointSizeAA = MAX_POINT_SIZE;
- ctx->Const.PointSizeGranularity = (GLfloat) POINT_SIZE_GRANULARITY;
- ctx->Const.MinLineWidth = MIN_LINE_WIDTH;
- ctx->Const.MaxLineWidth = MAX_LINE_WIDTH;
- ctx->Const.MinLineWidthAA = MIN_LINE_WIDTH;
- ctx->Const.MaxLineWidthAA = MAX_LINE_WIDTH;
- ctx->Const.LineWidthGranularity = (GLfloat) LINE_WIDTH_GRANULARITY;
- ctx->Const.MaxColorTableSize = MAX_COLOR_TABLE_SIZE;
- ctx->Const.MaxClipPlanes = MAX_CLIP_PLANES;
- ctx->Const.MaxLights = MAX_LIGHTS;
- ctx->Const.MaxShininess = 128.0;
- ctx->Const.MaxSpotExponent = 128.0;
- ctx->Const.MaxViewportWidth = MAX_WIDTH;
- ctx->Const.MaxViewportHeight = MAX_HEIGHT;
-#if FEATURE_ARB_vertex_program
- init_program_limits(GL_VERTEX_PROGRAM_ARB, &ctx->Const.VertexProgram);
-#endif
-#if FEATURE_ARB_fragment_program
- init_program_limits(GL_FRAGMENT_PROGRAM_ARB, &ctx->Const.FragmentProgram);
-#endif
-#if FEATURE_ARB_geometry_shader4
- init_program_limits(MESA_GEOMETRY_PROGRAM, &ctx->Const.GeometryProgram);
-#endif
- ctx->Const.MaxProgramMatrices = MAX_PROGRAM_MATRICES;
- ctx->Const.MaxProgramMatrixStackDepth = MAX_PROGRAM_MATRIX_STACK_DEPTH;
-
- /* CheckArrayBounds is overriden by drivers/x11 for X server */
- ctx->Const.CheckArrayBounds = GL_FALSE;
-
- /* GL_ARB_draw_buffers */
- ctx->Const.MaxDrawBuffers = MAX_DRAW_BUFFERS;
-
-#if FEATURE_EXT_framebuffer_object
- ctx->Const.MaxColorAttachments = MAX_COLOR_ATTACHMENTS;
- ctx->Const.MaxRenderbufferSize = MAX_WIDTH;
-#endif
-
-#if FEATURE_ARB_vertex_shader
- ctx->Const.MaxVertexTextureImageUnits = MAX_VERTEX_TEXTURE_IMAGE_UNITS;
- ctx->Const.MaxCombinedTextureImageUnits = MAX_COMBINED_TEXTURE_IMAGE_UNITS;
- ctx->Const.MaxVarying = MAX_VARYING;
-#endif
-#if FEATURE_ARB_geometry_shader4
- ctx->Const.MaxGeometryTextureImageUnits = MAX_GEOMETRY_TEXTURE_IMAGE_UNITS;
- ctx->Const.MaxVertexVaryingComponents = MAX_VERTEX_VARYING_COMPONENTS;
- ctx->Const.MaxGeometryVaryingComponents = MAX_GEOMETRY_VARYING_COMPONENTS;
- ctx->Const.MaxGeometryOutputVertices = MAX_GEOMETRY_OUTPUT_VERTICES;
- ctx->Const.MaxGeometryTotalOutputComponents = MAX_GEOMETRY_TOTAL_OUTPUT_COMPONENTS;
-#endif
-
- /* Shading language version */
- if (ctx->API == API_OPENGL) {
- ctx->Const.GLSLVersion = 120;
- }
- else if (ctx->API == API_OPENGLES2) {
- ctx->Const.GLSLVersion = 100;
- }
- else if (ctx->API == API_OPENGLES) {
- ctx->Const.GLSLVersion = 0; /* GLSL not supported */
- }
-
- /* GL_ARB_framebuffer_object */
- ctx->Const.MaxSamples = 0;
-
- /* GL_ARB_sync */
- ctx->Const.MaxServerWaitTimeout = (GLuint64) ~0;
-
- /* GL_ATI_envmap_bumpmap */
- ctx->Const.SupportedBumpUnits = SUPPORTED_ATI_BUMP_UNITS;
-
- /* GL_EXT_provoking_vertex */
- ctx->Const.QuadsFollowProvokingVertexConvention = GL_TRUE;
-
- /* GL_EXT_transform_feedback */
- ctx->Const.MaxTransformFeedbackSeparateAttribs = MAX_FEEDBACK_ATTRIBS;
- ctx->Const.MaxTransformFeedbackSeparateComponents = 4 * MAX_FEEDBACK_ATTRIBS;
- ctx->Const.MaxTransformFeedbackInterleavedComponents = 4 * MAX_FEEDBACK_ATTRIBS;
-
- /* GL 3.2: hard-coded for now: */
- ctx->Const.ProfileMask = GL_CONTEXT_COMPATIBILITY_PROFILE_BIT;
-
- /** GL_EXT_gpu_shader4 */
- ctx->Const.MinProgramTexelOffset = -8;
- ctx->Const.MaxProgramTexelOffset = 7;
-}
-
-
-/**
- * Do some sanity checks on the limits/constants for the given context.
- * Only called the first time a context is bound.
- */
-static void
-check_context_limits(struct gl_context *ctx)
-{
- /* check that we don't exceed the size of various bitfields */
- assert(VERT_RESULT_MAX <=
- (8 * sizeof(ctx->VertexProgram._Current->Base.OutputsWritten)));
- assert(FRAG_ATTRIB_MAX <=
- (8 * sizeof(ctx->FragmentProgram._Current->Base.InputsRead)));
-
- assert(MAX_COMBINED_TEXTURE_IMAGE_UNITS <= 8 * sizeof(GLbitfield));
-
- /* shader-related checks */
- assert(ctx->Const.FragmentProgram.MaxLocalParams <= MAX_PROGRAM_LOCAL_PARAMS);
- assert(ctx->Const.VertexProgram.MaxLocalParams <= MAX_PROGRAM_LOCAL_PARAMS);
-
- assert(MAX_NV_FRAGMENT_PROGRAM_TEMPS <= MAX_PROGRAM_TEMPS);
- assert(MAX_NV_VERTEX_PROGRAM_TEMPS <= MAX_PROGRAM_TEMPS);
- assert(MAX_NV_VERTEX_PROGRAM_INPUTS <= VERT_ATTRIB_MAX);
- assert(MAX_NV_VERTEX_PROGRAM_OUTPUTS <= VERT_RESULT_MAX);
-
- /* Texture unit checks */
- assert(ctx->Const.MaxTextureImageUnits > 0);
- assert(ctx->Const.MaxTextureImageUnits <= MAX_TEXTURE_IMAGE_UNITS);
- assert(ctx->Const.MaxTextureCoordUnits > 0);
- assert(ctx->Const.MaxTextureCoordUnits <= MAX_TEXTURE_COORD_UNITS);
- assert(ctx->Const.MaxTextureUnits > 0);
- assert(ctx->Const.MaxTextureUnits <= MAX_TEXTURE_IMAGE_UNITS);
- assert(ctx->Const.MaxTextureUnits <= MAX_TEXTURE_COORD_UNITS);
- assert(ctx->Const.MaxTextureUnits == MIN2(ctx->Const.MaxTextureImageUnits,
- ctx->Const.MaxTextureCoordUnits));
- assert(ctx->Const.MaxCombinedTextureImageUnits > 0);
- assert(ctx->Const.MaxCombinedTextureImageUnits <= MAX_COMBINED_TEXTURE_IMAGE_UNITS);
- assert(ctx->Const.MaxTextureCoordUnits <= MAX_COMBINED_TEXTURE_IMAGE_UNITS);
- /* number of coord units cannot be greater than number of image units */
- assert(ctx->Const.MaxTextureCoordUnits <= ctx->Const.MaxTextureImageUnits);
-
-
- /* Texture size checks */
- assert(ctx->Const.MaxTextureLevels <= MAX_TEXTURE_LEVELS);
- assert(ctx->Const.Max3DTextureLevels <= MAX_3D_TEXTURE_LEVELS);
- assert(ctx->Const.MaxCubeTextureLevels <= MAX_CUBE_TEXTURE_LEVELS);
- assert(ctx->Const.MaxTextureRectSize <= MAX_TEXTURE_RECT_SIZE);
-
- /* make sure largest texture image is <= MAX_WIDTH in size */
- assert((1 << (ctx->Const.MaxTextureLevels - 1)) <= MAX_WIDTH);
- assert((1 << (ctx->Const.MaxCubeTextureLevels - 1)) <= MAX_WIDTH);
- assert((1 << (ctx->Const.Max3DTextureLevels - 1)) <= MAX_WIDTH);
-
- /* Texture level checks */
- assert(MAX_TEXTURE_LEVELS >= MAX_3D_TEXTURE_LEVELS);
- assert(MAX_TEXTURE_LEVELS >= MAX_CUBE_TEXTURE_LEVELS);
-
- /* Max texture size should be <= max viewport size (render to texture) */
- assert((1 << (MAX_TEXTURE_LEVELS - 1)) <= MAX_WIDTH);
-
- assert(ctx->Const.MaxViewportWidth <= MAX_WIDTH);
- assert(ctx->Const.MaxViewportHeight <= MAX_WIDTH);
-
- assert(ctx->Const.MaxDrawBuffers <= MAX_DRAW_BUFFERS);
-
- /* if this fails, add more enum values to gl_buffer_index */
- assert(BUFFER_COLOR0 + MAX_DRAW_BUFFERS <= BUFFER_COUNT);
-
- /* XXX probably add more tests */
-}
-
-
-/**
- * Initialize the attribute groups in a GL context.
- *
- * \param ctx GL context.
- *
- * Initializes all the attributes, calling the respective <tt>init*</tt>
- * functions for the more complex data structures.
- */
-static GLboolean
-init_attrib_groups(struct gl_context *ctx)
-{
- assert(ctx);
-
- /* Constants */
- _mesa_init_constants( ctx );
-
- /* Extensions */
- _mesa_init_extensions( ctx );
-
- /* Attribute Groups */
- _mesa_init_accum( ctx );
- _mesa_init_attrib( ctx );
- _mesa_init_buffer_objects( ctx );
- _mesa_init_color( ctx );
- _mesa_init_current( ctx );
- _mesa_init_depth( ctx );
- _mesa_init_debug( ctx );
- _mesa_init_display_list( ctx );
- _mesa_init_eval( ctx );
- _mesa_init_fbobjects( ctx );
- _mesa_init_feedback( ctx );
- _mesa_init_fog( ctx );
- _mesa_init_hint( ctx );
- _mesa_init_line( ctx );
- _mesa_init_lighting( ctx );
- _mesa_init_matrix( ctx );
- _mesa_init_multisample( ctx );
- _mesa_init_pixel( ctx );
- _mesa_init_pixelstore( ctx );
- _mesa_init_point( ctx );
- _mesa_init_polygon( ctx );
- _mesa_init_program( ctx );
- _mesa_init_queryobj( ctx );
- _mesa_init_sync( ctx );
- _mesa_init_rastpos( ctx );
- _mesa_init_scissor( ctx );
- _mesa_init_shader_state( ctx );
- _mesa_init_stencil( ctx );
- _mesa_init_transform( ctx );
- _mesa_init_transform_feedback( ctx );
- _mesa_init_varray( ctx );
- _mesa_init_viewport( ctx );
-
- if (!_mesa_init_texture( ctx ))
- return GL_FALSE;
-
- _mesa_init_texture_s3tc( ctx );
-
- /* Miscellaneous */
- ctx->NewState = _NEW_ALL;
- ctx->ErrorValue = (GLenum) GL_NO_ERROR;
- ctx->varying_vp_inputs = ~0;
-
- return GL_TRUE;
-}
-
-
-/**
- * Update default objects in a GL context with respect to shared state.
- *
- * \param ctx GL context.
- *
- * Removes references to old default objects, (texture objects, program
- * objects, etc.) and changes to reference those from the current shared
- * state.
- */
-static GLboolean
-update_default_objects(struct gl_context *ctx)
-{
- assert(ctx);
-
- _mesa_update_default_objects_program(ctx);
- _mesa_update_default_objects_texture(ctx);
- _mesa_update_default_objects_buffer_objects(ctx);
-
- return GL_TRUE;
-}
-
-
-/**
- * This is the default function we plug into all dispatch table slots
- * This helps prevents a segfault when someone calls a GL function without
- * first checking if the extension's supported.
- */
-static int
-generic_nop(void)
-{
- _mesa_warning(NULL, "User called no-op dispatch function (an unsupported extension function?)");
- return 0;
-}
-
-
-/**
- * Allocate and initialize a new dispatch table.
- */
-struct _glapi_table *
-_mesa_alloc_dispatch_table(int size)
-{
- /* Find the larger of Mesa's dispatch table and libGL's dispatch table.
- * In practice, this'll be the same for stand-alone Mesa. But for DRI
- * Mesa we do this to accomodate different versions of libGL and various
- * DRI drivers.
- */
- GLint numEntries = MAX2(_glapi_get_dispatch_table_size(), _gloffset_COUNT);
- struct _glapi_table *table;
-
- /* should never happen, but just in case */
- numEntries = MAX2(numEntries, size);
-
- table = (struct _glapi_table *) malloc(numEntries * sizeof(_glapi_proc));
- if (table) {
- _glapi_proc *entry = (_glapi_proc *) table;
- GLint i;
- for (i = 0; i < numEntries; i++) {
- entry[i] = (_glapi_proc) generic_nop;
- }
- }
- return table;
-}
-
-
-/**
- * Initialize a struct gl_context struct (rendering context).
- *
- * This includes allocating all the other structs and arrays which hang off of
- * the context by pointers.
- * Note that the driver needs to pass in its dd_function_table here since
- * we need to at least call driverFunctions->NewTextureObject to create the
- * default texture objects.
- *
- * Called by _mesa_create_context().
- *
- * Performs the imports and exports callback tables initialization, and
- * miscellaneous one-time initializations. If no shared context is supplied one
- * is allocated, and increase its reference count. Setups the GL API dispatch
- * tables. Initialize the TNL module. Sets the maximum Z buffer depth.
- * Finally queries the \c MESA_DEBUG and \c MESA_VERBOSE environment variables
- * for debug flags.
- *
- * \param ctx the context to initialize
- * \param api the GL API type to create the context for
- * \param visual describes the visual attributes for this context
- * \param share_list points to context to share textures, display lists,
- * etc with, or NULL
- * \param driverFunctions table of device driver functions for this context
- * to use
- * \param driverContext pointer to driver-specific context data
- */
-GLboolean
-_mesa_initialize_context(struct gl_context *ctx,
- gl_api api,
- const struct gl_config *visual,
- struct gl_context *share_list,
- const struct dd_function_table *driverFunctions,
- void *driverContext)
-{
- struct gl_shared_state *shared;
- int i;
-
- /*ASSERT(driverContext);*/
- assert(driverFunctions->NewTextureObject);
- assert(driverFunctions->FreeTexImageData);
-
- ctx->API = api;
- ctx->Visual = *visual;
- ctx->DrawBuffer = NULL;
- ctx->ReadBuffer = NULL;
- ctx->WinSysDrawBuffer = NULL;
- ctx->WinSysReadBuffer = NULL;
-
- /* misc one-time initializations */
- one_time_init(ctx);
-
- /* Plug in driver functions and context pointer here.
- * This is important because when we call alloc_shared_state() below
- * we'll call ctx->Driver.NewTextureObject() to create the default
- * textures.
- */
- ctx->Driver = *driverFunctions;
- ctx->DriverCtx = driverContext;
-
- if (share_list) {
- /* share state with another context */
- shared = share_list->Shared;
- }
- else {
- /* allocate new, unshared state */
- shared = _mesa_alloc_shared_state(ctx);
- if (!shared)
- return GL_FALSE;
- }
-
- _glthread_LOCK_MUTEX(shared->Mutex);
- ctx->Shared = shared;
- shared->RefCount++;
- _glthread_UNLOCK_MUTEX(shared->Mutex);
-
- if (!init_attrib_groups( ctx )) {
- _mesa_release_shared_state(ctx, ctx->Shared);
- return GL_FALSE;
- }
-
-#if FEATURE_dispatch
- /* setup the API dispatch tables */
- switch (ctx->API) {
-#if FEATURE_GL
- case API_OPENGL:
- ctx->Exec = _mesa_create_exec_table();
- break;
-#endif
-#if FEATURE_ES1
- case API_OPENGLES:
- ctx->Exec = _mesa_create_exec_table_es1();
- break;
-#endif
-#if FEATURE_ES2
- case API_OPENGLES2:
- ctx->Exec = _mesa_create_exec_table_es2();
- break;
-#endif
- default:
- _mesa_problem(ctx, "unknown or unsupported API");
- break;
- }
-
- if (!ctx->Exec) {
- _mesa_release_shared_state(ctx, ctx->Shared);
- return GL_FALSE;
- }
-#endif
- ctx->CurrentDispatch = ctx->Exec;
-
- ctx->FragmentProgram._MaintainTexEnvProgram
- = (_mesa_getenv("MESA_TEX_PROG") != NULL);
-
- ctx->VertexProgram._MaintainTnlProgram
- = (_mesa_getenv("MESA_TNL_PROG") != NULL);
- if (ctx->VertexProgram._MaintainTnlProgram) {
- /* this is required... */
- ctx->FragmentProgram._MaintainTexEnvProgram = GL_TRUE;
- }
-
- /* Mesa core handles all the formats that mesa core knows about.
- * Drivers will want to override this list with just the formats
- * they can handle, and confirm that appropriate fallbacks exist in
- * _mesa_choose_tex_format().
- */
- memset(&ctx->TextureFormatSupported, GL_TRUE,
- sizeof(ctx->TextureFormatSupported));
-
- switch (ctx->API) {
- case API_OPENGL:
-#if FEATURE_dlist
- ctx->Save = _mesa_create_save_table();
- if (!ctx->Save) {
- _mesa_release_shared_state(ctx, ctx->Shared);
- free(ctx->Exec);
- return GL_FALSE;
- }
-
- _mesa_install_save_vtxfmt( ctx, &ctx->ListState.ListVtxfmt );
-#endif
- break;
- case API_OPENGLES:
- /**
- * GL_OES_texture_cube_map says
- * "Initially all texture generation modes are set to REFLECTION_MAP_OES"
- */
- for (i = 0; i < MAX_TEXTURE_UNITS; i++) {
- struct gl_texture_unit *texUnit = &ctx->Texture.Unit[i];
- texUnit->GenS.Mode = GL_REFLECTION_MAP_NV;
- texUnit->GenT.Mode = GL_REFLECTION_MAP_NV;
- texUnit->GenR.Mode = GL_REFLECTION_MAP_NV;
- texUnit->GenS._ModeBit = TEXGEN_REFLECTION_MAP_NV;
- texUnit->GenT._ModeBit = TEXGEN_REFLECTION_MAP_NV;
- texUnit->GenR._ModeBit = TEXGEN_REFLECTION_MAP_NV;
- }
- break;
- case API_OPENGLES2:
- ctx->FragmentProgram._MaintainTexEnvProgram = GL_TRUE;
- ctx->VertexProgram._MaintainTnlProgram = GL_TRUE;
- ctx->Point.PointSprite = GL_TRUE; /* always on for ES 2.x */
- break;
- }
-
- ctx->FirstTimeCurrent = GL_TRUE;
-
- return GL_TRUE;
-}
-
-
-/**
- * Allocate and initialize a struct gl_context structure.
- * Note that the driver needs to pass in its dd_function_table here since
- * we need to at least call driverFunctions->NewTextureObject to initialize
- * the rendering context.
- *
- * \param api the GL API type to create the context for
- * \param visual a struct gl_config pointer (we copy the struct contents)
- * \param share_list another context to share display lists with or NULL
- * \param driverFunctions points to the dd_function_table into which the
- * driver has plugged in all its special functions.
- * \param driverContext points to the device driver's private context state
- *
- * \return pointer to a new __struct gl_contextRec or NULL if error.
- */
-struct gl_context *
-_mesa_create_context(gl_api api,
- const struct gl_config *visual,
- struct gl_context *share_list,
- const struct dd_function_table *driverFunctions,
- void *driverContext)
-{
- struct gl_context *ctx;
-
- ASSERT(visual);
- /*ASSERT(driverContext);*/
-
- ctx = (struct gl_context *) calloc(1, sizeof(struct gl_context));
- if (!ctx)
- return NULL;
-
- if (_mesa_initialize_context(ctx, api, visual, share_list,
- driverFunctions, driverContext)) {
- return ctx;
- }
- else {
- free(ctx);
- return NULL;
- }
-}
-
-
-/**
- * Free the data associated with the given context.
- *
- * But doesn't free the struct gl_context struct itself.
- *
- * \sa _mesa_initialize_context() and init_attrib_groups().
- */
-void
-_mesa_free_context_data( struct gl_context *ctx )
-{
- if (!_mesa_get_current_context()){
- /* No current context, but we may need one in order to delete
- * texture objs, etc. So temporarily bind the context now.
- */
- _mesa_make_current(ctx, NULL, NULL);
- }
-
- /* unreference WinSysDraw/Read buffers */
- _mesa_reference_framebuffer(&ctx->WinSysDrawBuffer, NULL);
- _mesa_reference_framebuffer(&ctx->WinSysReadBuffer, NULL);
- _mesa_reference_framebuffer(&ctx->DrawBuffer, NULL);
- _mesa_reference_framebuffer(&ctx->ReadBuffer, NULL);
-
- _mesa_reference_vertprog(ctx, &ctx->VertexProgram.Current, NULL);
- _mesa_reference_vertprog(ctx, &ctx->VertexProgram._Current, NULL);
- _mesa_reference_vertprog(ctx, &ctx->VertexProgram._TnlProgram, NULL);
-
- _mesa_reference_fragprog(ctx, &ctx->FragmentProgram.Current, NULL);
- _mesa_reference_fragprog(ctx, &ctx->FragmentProgram._Current, NULL);
- _mesa_reference_fragprog(ctx, &ctx->FragmentProgram._TexEnvProgram, NULL);
-
- _mesa_free_attrib_data(ctx);
- _mesa_free_buffer_objects(ctx);
- _mesa_free_lighting_data( ctx );
- _mesa_free_eval_data( ctx );
- _mesa_free_texture_data( ctx );
- _mesa_free_matrix_data( ctx );
- _mesa_free_viewport_data( ctx );
- _mesa_free_program_data(ctx);
- _mesa_free_shader_state(ctx);
- _mesa_free_queryobj_data(ctx);
- _mesa_free_sync_data(ctx);
- _mesa_free_varray_data(ctx);
- _mesa_free_transform_feedback(ctx);
-
- _mesa_delete_array_object(ctx, ctx->Array.DefaultArrayObj);
-
-#if FEATURE_ARB_pixel_buffer_object
- _mesa_reference_buffer_object(ctx, &ctx->Pack.BufferObj, NULL);
- _mesa_reference_buffer_object(ctx, &ctx->Unpack.BufferObj, NULL);
- _mesa_reference_buffer_object(ctx, &ctx->DefaultPacking.BufferObj, NULL);
-#endif
-
-#if FEATURE_ARB_vertex_buffer_object
- _mesa_reference_buffer_object(ctx, &ctx->Array.ArrayBufferObj, NULL);
- _mesa_reference_buffer_object(ctx, &ctx->Array.ElementArrayBufferObj, NULL);
-#endif
-
- /* free dispatch tables */
- free(ctx->Exec);
- free(ctx->Save);
-
- /* Shared context state (display lists, textures, etc) */
- _mesa_release_shared_state( ctx, ctx->Shared );
-
- /* needs to be after freeing shared state */
- _mesa_free_display_list_data(ctx);
-
- if (ctx->Extensions.String)
- free((void *) ctx->Extensions.String);
-
- if (ctx->VersionString)
- free(ctx->VersionString);
-
- /* unbind the context if it's currently bound */
- if (ctx == _mesa_get_current_context()) {
- _mesa_make_current(NULL, NULL, NULL);
- }
-}
-
-
-/**
- * Destroy a struct gl_context structure.
- *
- * \param ctx GL context.
- *
- * Calls _mesa_free_context_data() and frees the gl_context object itself.
- */
-void
-_mesa_destroy_context( struct gl_context *ctx )
-{
- if (ctx) {
- _mesa_free_context_data(ctx);
- free( (void *) ctx );
- }
-}
-
-
-#if _HAVE_FULL_GL
-/**
- * Copy attribute groups from one context to another.
- *
- * \param src source context
- * \param dst destination context
- * \param mask bitwise OR of GL_*_BIT flags
- *
- * According to the bits specified in \p mask, copies the corresponding
- * attributes from \p src into \p dst. For many of the attributes a simple \c
- * memcpy is not enough due to the existence of internal pointers in their data
- * structures.
- */
-void
-_mesa_copy_context( const struct gl_context *src, struct gl_context *dst, GLuint mask )
-{
- if (mask & GL_ACCUM_BUFFER_BIT) {
- /* OK to memcpy */
- dst->Accum = src->Accum;
- }
- if (mask & GL_COLOR_BUFFER_BIT) {
- /* OK to memcpy */
- dst->Color = src->Color;
- }
- if (mask & GL_CURRENT_BIT) {
- /* OK to memcpy */
- dst->Current = src->Current;
- }
- if (mask & GL_DEPTH_BUFFER_BIT) {
- /* OK to memcpy */
- dst->Depth = src->Depth;
- }
- if (mask & GL_ENABLE_BIT) {
- /* no op */
- }
- if (mask & GL_EVAL_BIT) {
- /* OK to memcpy */
- dst->Eval = src->Eval;
- }
- if (mask & GL_FOG_BIT) {
- /* OK to memcpy */
- dst->Fog = src->Fog;
- }
- if (mask & GL_HINT_BIT) {
- /* OK to memcpy */
- dst->Hint = src->Hint;
- }
- if (mask & GL_LIGHTING_BIT) {
- GLuint i;
- /* begin with memcpy */
- dst->Light = src->Light;
- /* fixup linked lists to prevent pointer insanity */
- make_empty_list( &(dst->Light.EnabledList) );
- for (i = 0; i < MAX_LIGHTS; i++) {
- if (dst->Light.Light[i].Enabled) {
- insert_at_tail(&(dst->Light.EnabledList), &(dst->Light.Light[i]));
- }
- }
- }
- if (mask & GL_LINE_BIT) {
- /* OK to memcpy */
- dst->Line = src->Line;
- }
- if (mask & GL_LIST_BIT) {
- /* OK to memcpy */
- dst->List = src->List;
- }
- if (mask & GL_PIXEL_MODE_BIT) {
- /* OK to memcpy */
- dst->Pixel = src->Pixel;
- }
- if (mask & GL_POINT_BIT) {
- /* OK to memcpy */
- dst->Point = src->Point;
- }
- if (mask & GL_POLYGON_BIT) {
- /* OK to memcpy */
- dst->Polygon = src->Polygon;
- }
- if (mask & GL_POLYGON_STIPPLE_BIT) {
- /* Use loop instead of memcpy due to problem with Portland Group's
- * C compiler. Reported by John Stone.
- */
- GLuint i;
- for (i = 0; i < 32; i++) {
- dst->PolygonStipple[i] = src->PolygonStipple[i];
- }
- }
- if (mask & GL_SCISSOR_BIT) {
- /* OK to memcpy */
- dst->Scissor = src->Scissor;
- }
- if (mask & GL_STENCIL_BUFFER_BIT) {
- /* OK to memcpy */
- dst->Stencil = src->Stencil;
- }
- if (mask & GL_TEXTURE_BIT) {
- /* Cannot memcpy because of pointers */
- _mesa_copy_texture_state(src, dst);
- }
- if (mask & GL_TRANSFORM_BIT) {
- /* OK to memcpy */
- dst->Transform = src->Transform;
- }
- if (mask & GL_VIEWPORT_BIT) {
- /* Cannot use memcpy, because of pointers in GLmatrix _WindowMap */
- dst->Viewport.X = src->Viewport.X;
- dst->Viewport.Y = src->Viewport.Y;
- dst->Viewport.Width = src->Viewport.Width;
- dst->Viewport.Height = src->Viewport.Height;
- dst->Viewport.Near = src->Viewport.Near;
- dst->Viewport.Far = src->Viewport.Far;
- _math_matrix_copy(&dst->Viewport._WindowMap, &src->Viewport._WindowMap);
- }
-
- /* XXX FIXME: Call callbacks?
- */
- dst->NewState = _NEW_ALL;
-}
-#endif
-
-
-/**
- * Check if the given context can render into the given framebuffer
- * by checking visual attributes.
- *
- * Most of these tests could go away because Mesa is now pretty flexible
- * in terms of mixing rendering contexts with framebuffers. As long
- * as RGB vs. CI mode agree, we're probably good.
- *
- * \return GL_TRUE if compatible, GL_FALSE otherwise.
- */
-static GLboolean
-check_compatible(const struct gl_context *ctx,
- const struct gl_framebuffer *buffer)
-{
- const struct gl_config *ctxvis = &ctx->Visual;
- const struct gl_config *bufvis = &buffer->Visual;
-
- if (buffer == _mesa_get_incomplete_framebuffer())
- return GL_TRUE;
-
-#if 0
- /* disabling this fixes the fgl_glxgears pbuffer demo */
- if (ctxvis->doubleBufferMode && !bufvis->doubleBufferMode)
- return GL_FALSE;
-#endif
- if (ctxvis->stereoMode && !bufvis->stereoMode)
- return GL_FALSE;
- if (ctxvis->haveAccumBuffer && !bufvis->haveAccumBuffer)
- return GL_FALSE;
- if (ctxvis->haveDepthBuffer && !bufvis->haveDepthBuffer)
- return GL_FALSE;
- if (ctxvis->haveStencilBuffer && !bufvis->haveStencilBuffer)
- return GL_FALSE;
- if (ctxvis->redMask && ctxvis->redMask != bufvis->redMask)
- return GL_FALSE;
- if (ctxvis->greenMask && ctxvis->greenMask != bufvis->greenMask)
- return GL_FALSE;
- if (ctxvis->blueMask && ctxvis->blueMask != bufvis->blueMask)
- return GL_FALSE;
-#if 0
- /* disabled (see bug 11161) */
- if (ctxvis->depthBits && ctxvis->depthBits != bufvis->depthBits)
- return GL_FALSE;
-#endif
- if (ctxvis->stencilBits && ctxvis->stencilBits != bufvis->stencilBits)
- return GL_FALSE;
-
- return GL_TRUE;
-}
-
-
-/**
- * Do one-time initialization for the given framebuffer. Specifically,
- * ask the driver for the window's current size and update the framebuffer
- * object to match.
- * Really, the device driver should totally take care of this.
- */
-static void
-initialize_framebuffer_size(struct gl_context *ctx, struct gl_framebuffer *fb)
-{
- GLuint width, height;
- if (ctx->Driver.GetBufferSize) {
- ctx->Driver.GetBufferSize(fb, &width, &height);
- if (ctx->Driver.ResizeBuffers)
- ctx->Driver.ResizeBuffers(ctx, fb, width, height);
- fb->Initialized = GL_TRUE;
- }
-}
-
-
-/**
- * Check if the viewport/scissor size has not yet been initialized.
- * Initialize the size if the given width and height are non-zero.
- */
-void
-_mesa_check_init_viewport(struct gl_context *ctx, GLuint width, GLuint height)
-{
- if (!ctx->ViewportInitialized && width > 0 && height > 0) {
- /* Note: set flag here, before calling _mesa_set_viewport(), to prevent
- * potential infinite recursion.
- */
- ctx->ViewportInitialized = GL_TRUE;
- _mesa_set_viewport(ctx, 0, 0, width, height);
- _mesa_set_scissor(ctx, 0, 0, width, height);
- }
-}
-
-
-/**
- * Bind the given context to the given drawBuffer and readBuffer and
- * make it the current context for the calling thread.
- * We'll render into the drawBuffer and read pixels from the
- * readBuffer (i.e. glRead/CopyPixels, glCopyTexImage, etc).
- *
- * We check that the context's and framebuffer's visuals are compatible
- * and return immediately if they're not.
- *
- * \param newCtx the new GL context. If NULL then there will be no current GL
- * context.
- * \param drawBuffer the drawing framebuffer
- * \param readBuffer the reading framebuffer
- */
-GLboolean
-_mesa_make_current( struct gl_context *newCtx,
- struct gl_framebuffer *drawBuffer,
- struct gl_framebuffer *readBuffer )
-{
- GET_CURRENT_CONTEXT(curCtx);
-
- if (MESA_VERBOSE & VERBOSE_API)
- _mesa_debug(newCtx, "_mesa_make_current()\n");
-
- /* Check that the context's and framebuffer's visuals are compatible.
- */
- if (newCtx && drawBuffer && newCtx->WinSysDrawBuffer != drawBuffer) {
- if (!check_compatible(newCtx, drawBuffer)) {
- _mesa_warning(newCtx,
- "MakeCurrent: incompatible visuals for context and drawbuffer");
- return GL_FALSE;
- }
- }
- if (newCtx && readBuffer && newCtx->WinSysReadBuffer != readBuffer) {
- if (!check_compatible(newCtx, readBuffer)) {
- _mesa_warning(newCtx,
- "MakeCurrent: incompatible visuals for context and readbuffer");
- return GL_FALSE;
- }
- }
-
- if (curCtx &&
- (curCtx->WinSysDrawBuffer || curCtx->WinSysReadBuffer) && /* make sure this context is valid for flushing */
- curCtx != newCtx)
- _mesa_flush(curCtx);
-
- /* We used to call _glapi_check_multithread() here. Now do it in drivers */
- _glapi_set_context((void *) newCtx);
- ASSERT(_mesa_get_current_context() == newCtx);
-
- if (!newCtx) {
- _glapi_set_dispatch(NULL); /* none current */
- }
- else {
- _glapi_set_dispatch(newCtx->CurrentDispatch);
-
- if (drawBuffer && readBuffer) {
- /* TODO: check if newCtx and buffer's visual match??? */
-
- ASSERT(drawBuffer->Name == 0);
- ASSERT(readBuffer->Name == 0);
- _mesa_reference_framebuffer(&newCtx->WinSysDrawBuffer, drawBuffer);
- _mesa_reference_framebuffer(&newCtx->WinSysReadBuffer, readBuffer);
-
- /*
- * Only set the context's Draw/ReadBuffer fields if they're NULL
- * or not bound to a user-created FBO.
- */
- if (!newCtx->DrawBuffer || newCtx->DrawBuffer->Name == 0) {
- /* KW: merge conflict here, revisit.
- */
- /* fix up the fb fields - these will end up wrong otherwise
- * if the DRIdrawable changes, and everything relies on them.
- * This is a bit messy (same as needed in _mesa_BindFramebufferEXT)
- */
- unsigned int i;
- GLenum buffers[MAX_DRAW_BUFFERS];
-
- _mesa_reference_framebuffer(&newCtx->DrawBuffer, drawBuffer);
-
- for(i = 0; i < newCtx->Const.MaxDrawBuffers; i++) {
- buffers[i] = newCtx->Color.DrawBuffer[i];
- }
-
- _mesa_drawbuffers(newCtx, newCtx->Const.MaxDrawBuffers,
- buffers, NULL);
- }
- if (!newCtx->ReadBuffer || newCtx->ReadBuffer->Name == 0) {
- _mesa_reference_framebuffer(&newCtx->ReadBuffer, readBuffer);
- }
-
- /* XXX only set this flag if we're really changing the draw/read
- * framebuffer bindings.
- */
- newCtx->NewState |= _NEW_BUFFERS;
-
-#if 1
- /* We want to get rid of these lines: */
-
-#if _HAVE_FULL_GL
- if (!drawBuffer->Initialized) {
- initialize_framebuffer_size(newCtx, drawBuffer);
- }
- if (readBuffer != drawBuffer && !readBuffer->Initialized) {
- initialize_framebuffer_size(newCtx, readBuffer);
- }
-
- _mesa_resizebuffers(newCtx);
-#endif
-
-#else
- /* We want the drawBuffer and readBuffer to be initialized by
- * the driver.
- * This generally means the Width and Height match the actual
- * window size and the renderbuffers (both hardware and software
- * based) are allocated to match. The later can generally be
- * done with a call to _mesa_resize_framebuffer().
- *
- * It's theoretically possible for a buffer to have zero width
- * or height, but for now, assert check that the driver did what's
- * expected of it.
- */
- ASSERT(drawBuffer->Width > 0);
- ASSERT(drawBuffer->Height > 0);
-#endif
-
- if (drawBuffer) {
- _mesa_check_init_viewport(newCtx,
- drawBuffer->Width, drawBuffer->Height);
- }
- }
-
- if (newCtx->FirstTimeCurrent) {
- _mesa_compute_version(newCtx);
-
- newCtx->Extensions.String = _mesa_make_extension_string(newCtx);
-
- check_context_limits(newCtx);
-
- /* We can use this to help debug user's problems. Tell them to set
- * the MESA_INFO env variable before running their app. Then the
- * first time each context is made current we'll print some useful
- * information.
- */
- if (_mesa_getenv("MESA_INFO")) {
- _mesa_print_info();
- }
-
- newCtx->FirstTimeCurrent = GL_FALSE;
- }
- }
-
- return GL_TRUE;
-}
-
-
-/**
- * Make context 'ctx' share the display lists, textures and programs
- * that are associated with 'ctxToShare'.
- * Any display lists, textures or programs associated with 'ctx' will
- * be deleted if nobody else is sharing them.
- */
-GLboolean
-_mesa_share_state(struct gl_context *ctx, struct gl_context *ctxToShare)
-{
- if (ctx && ctxToShare && ctx->Shared && ctxToShare->Shared) {
- struct gl_shared_state *oldSharedState = ctx->Shared;
-
- ctx->Shared = ctxToShare->Shared;
-
- _glthread_LOCK_MUTEX(ctx->Shared->Mutex);
- ctx->Shared->RefCount++;
- _glthread_UNLOCK_MUTEX(ctx->Shared->Mutex);
-
- update_default_objects(ctx);
-
- _mesa_release_shared_state(ctx, oldSharedState);
-
- return GL_TRUE;
- }
- else {
- return GL_FALSE;
- }
-}
-
-
-
-/**
- * \return pointer to the current GL context for this thread.
- *
- * Calls _glapi_get_context(). This isn't the fastest way to get the current
- * context. If you need speed, see the #GET_CURRENT_CONTEXT macro in
- * context.h.
- */
-struct gl_context *
-_mesa_get_current_context( void )
-{
- return (struct gl_context *) _glapi_get_context();
-}
-
-
-/**
- * Get context's current API dispatch table.
- *
- * It'll either be the immediate-mode execute dispatcher or the display list
- * compile dispatcher.
- *
- * \param ctx GL context.
- *
- * \return pointer to dispatch_table.
- *
- * Simply returns __struct gl_contextRec::CurrentDispatch.
- */
-struct _glapi_table *
-_mesa_get_dispatch(struct gl_context *ctx)
-{
- return ctx->CurrentDispatch;
-}
-
-/*@}*/
-
-
-/**********************************************************************/
-/** \name Miscellaneous functions */
-/**********************************************************************/
-/*@{*/
-
-/**
- * Record an error.
- *
- * \param ctx GL context.
- * \param error error code.
- *
- * Records the given error code and call the driver's dd_function_table::Error
- * function if defined.
- *
- * \sa
- * This is called via _mesa_error().
- */
-void
-_mesa_record_error(struct gl_context *ctx, GLenum error)
-{
- if (!ctx)
- return;
-
- if (ctx->ErrorValue == GL_NO_ERROR) {
- ctx->ErrorValue = error;
- }
-
- /* Call device driver's error handler, if any. This is used on the Mac. */
- if (ctx->Driver.Error) {
- ctx->Driver.Error(ctx);
- }
-}
-
-
-/**
- * Flush commands and wait for completion.
- */
-void
-_mesa_finish(struct gl_context *ctx)
-{
- FLUSH_CURRENT( ctx, 0 );
- if (ctx->Driver.Finish) {
- ctx->Driver.Finish(ctx);
- }
-}
-
-
-/**
- * Flush commands.
- */
-void
-_mesa_flush(struct gl_context *ctx)
-{
- FLUSH_CURRENT( ctx, 0 );
- if (ctx->Driver.Flush) {
- ctx->Driver.Flush(ctx);
- }
-}
-
-
-
-/**
- * Execute glFinish().
- *
- * Calls the #ASSERT_OUTSIDE_BEGIN_END_AND_FLUSH macro and the
- * dd_function_table::Finish driver callback, if not NULL.
- */
-void GLAPIENTRY
-_mesa_Finish(void)
-{
- GET_CURRENT_CONTEXT(ctx);
- ASSERT_OUTSIDE_BEGIN_END_AND_FLUSH(ctx);
- _mesa_finish(ctx);
-}
-
-
-/**
- * Execute glFlush().
- *
- * Calls the #ASSERT_OUTSIDE_BEGIN_END_AND_FLUSH macro and the
- * dd_function_table::Flush driver callback, if not NULL.
- */
-void GLAPIENTRY
-_mesa_Flush(void)
-{
- GET_CURRENT_CONTEXT(ctx);
- ASSERT_OUTSIDE_BEGIN_END_AND_FLUSH(ctx);
- _mesa_flush(ctx);
-}
-
-
-/**
- * Set mvp_with_dp4 flag. If a driver has a preference for DP4 over
- * MUL/MAD, or vice versa, call this function to register that.
- * Otherwise we default to MUL/MAD.
- */
-void
-_mesa_set_mvp_with_dp4( struct gl_context *ctx,
- GLboolean flag )
-{
- ctx->mvp_with_dp4 = flag;
-}
-
-
-
-/**
- * Prior to drawing anything with glBegin, glDrawArrays, etc. this function
- * is called to see if it's valid to render. This involves checking that
- * the current shader is valid and the framebuffer is complete.
- * If an error is detected it'll be recorded here.
- * \return GL_TRUE if OK to render, GL_FALSE if not
- */
-GLboolean
-_mesa_valid_to_render(struct gl_context *ctx, const char *where)
-{
- bool vert_from_glsl_shader = false;
- bool geom_from_glsl_shader = false;
- bool frag_from_glsl_shader = false;
-
- /* This depends on having up to date derived state (shaders) */
- if (ctx->NewState)
- _mesa_update_state(ctx);
-
- if (ctx->Shader.CurrentVertexProgram) {
- vert_from_glsl_shader = true;
-
- if (!ctx->Shader.CurrentVertexProgram->LinkStatus) {
- _mesa_error(ctx, GL_INVALID_OPERATION,
- "%s(shader not linked)", where);
- return GL_FALSE;
- }
-#if 0 /* not normally enabled */
- {
- char errMsg[100];
- if (!_mesa_validate_shader_program(ctx,
- ctx->Shader.CurrentVertexProgram,
- errMsg)) {
- _mesa_warning(ctx, "Shader program %u is invalid: %s",
- ctx->Shader.CurrentVertexProgram->Name, errMsg);
- }
- }
-#endif
- }
-
- if (ctx->Shader.CurrentGeometryProgram) {
- geom_from_glsl_shader = true;
-
- if (!ctx->Shader.CurrentGeometryProgram->LinkStatus) {
- _mesa_error(ctx, GL_INVALID_OPERATION,
- "%s(shader not linked)", where);
- return GL_FALSE;
- }
-#if 0 /* not normally enabled */
- {
- char errMsg[100];
- if (!_mesa_validate_shader_program(ctx,
- ctx->Shader.CurrentGeometryProgram,
- errMsg)) {
- _mesa_warning(ctx, "Shader program %u is invalid: %s",
- ctx->Shader.CurrentGeometryProgram->Name, errMsg);
- }
- }
-#endif
- }
-
- if (ctx->Shader.CurrentFragmentProgram) {
- frag_from_glsl_shader = true;
-
- if (!ctx->Shader.CurrentFragmentProgram->LinkStatus) {
- _mesa_error(ctx, GL_INVALID_OPERATION,
- "%s(shader not linked)", where);
- return GL_FALSE;
- }
-#if 0 /* not normally enabled */
- {
- char errMsg[100];
- if (!_mesa_validate_shader_program(ctx,
- ctx->Shader.CurrentFragmentProgram,
- errMsg)) {
- _mesa_warning(ctx, "Shader program %u is invalid: %s",
- ctx->Shader.CurrentFragmentProgram->Name, errMsg);
- }
- }
-#endif
- }
-
- /* Any shader stages that are not supplied by the GLSL shader and have
- * assembly shaders enabled must now be validated.
- */
- if (!vert_from_glsl_shader
- && ctx->VertexProgram.Enabled && !ctx->VertexProgram._Enabled) {
- _mesa_error(ctx, GL_INVALID_OPERATION,
- "%s(vertex program not valid)", where);
- return GL_FALSE;
- }
-
- /* FINISHME: If GL_NV_geometry_program4 is ever supported, the current
- * FINISHME: geometry program should validated here.
- */
- (void) geom_from_glsl_shader;
-
- if (!frag_from_glsl_shader) {
- if (ctx->FragmentProgram.Enabled && !ctx->FragmentProgram._Enabled) {
- _mesa_error(ctx, GL_INVALID_OPERATION,
- "%s(fragment program not valid)", where);
- return GL_FALSE;
- }
-
- /* If drawing to integer-valued color buffers, there must be an
- * active fragment shader (GL_EXT_texture_integer).
- */
- if (ctx->DrawBuffer && ctx->DrawBuffer->_IntegerColor) {
- _mesa_error(ctx, GL_INVALID_OPERATION,
- "%s(integer format but no fragment shader)", where);
- return GL_FALSE;
- }
- }
-
- if (ctx->DrawBuffer->_Status != GL_FRAMEBUFFER_COMPLETE_EXT) {
- _mesa_error(ctx, GL_INVALID_FRAMEBUFFER_OPERATION_EXT,
- "%s(incomplete framebuffer)", where);
- return GL_FALSE;
- }
-
-#ifdef DEBUG
- if (ctx->Shader.Flags & GLSL_LOG) {
- struct gl_shader_program *shProg[MESA_SHADER_TYPES];
- gl_shader_type i;
-
- shProg[MESA_SHADER_VERTEX] = ctx->Shader.CurrentVertexProgram;
- shProg[MESA_SHADER_GEOMETRY] = ctx->Shader.CurrentGeometryProgram;
- shProg[MESA_SHADER_FRAGMENT] = ctx->Shader.CurrentFragmentProgram;
-
- for (i = 0; i < MESA_SHADER_TYPES; i++) {
- struct gl_shader *sh;
-
- if (shProg[i] == NULL || shProg[i]->_Used
- || shProg[i]->_LinkedShaders[i] == NULL)
- continue;
-
- /* This is the first time this shader is being used.
- * Append shader's constants/uniforms to log file.
- *
- * The logic is a little odd here. We only want to log data for each
- * shader target that will actually be used, and we only want to log
- * it once. It's possible to have a program bound to the vertex
- * shader target that also supplied a fragment shader. If that
- * program isn't also bound to the fragment shader target we don't
- * want to log its fragment data.
- */
- sh = shProg[i]->_LinkedShaders[i];
- switch (sh->Type) {
- case GL_VERTEX_SHADER:
- _mesa_append_uniforms_to_file(sh, &shProg[i]->VertexProgram->Base);
- break;
-
- case GL_GEOMETRY_SHADER_ARB:
- _mesa_append_uniforms_to_file(sh,
- &shProg[i]->GeometryProgram->Base);
- break;
-
- case GL_FRAGMENT_SHADER:
- _mesa_append_uniforms_to_file(sh,
- &shProg[i]->FragmentProgram->Base);
- break;
- }
- }
-
- for (i = 0; i < MESA_SHADER_TYPES; i++) {
- if (shProg[i] != NULL)
- shProg[i]->_Used = GL_TRUE;
- }
- }
-#endif
-
- return GL_TRUE;
-}
-
-
-/*@}*/
+/* + * Mesa 3-D graphics library + * Version: 7.3 + * + * Copyright (C) 1999-2007 Brian Paul All Rights Reserved. + * Copyright (C) 2008 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 + * BRIAN PAUL 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 context.c + * Mesa context/visual/framebuffer management functions. + * \author Brian Paul + */ + +/** + * \mainpage Mesa Main Module + * + * \section MainIntroduction Introduction + * + * The Mesa Main module consists of all the files in the main/ directory. + * Among the features of this module are: + * <UL> + * <LI> Structures to represent most GL state </LI> + * <LI> State set/get functions </LI> + * <LI> Display lists </LI> + * <LI> Texture unit, object and image handling </LI> + * <LI> Matrix and attribute stacks </LI> + * </UL> + * + * Other modules are responsible for API dispatch, vertex transformation, + * point/line/triangle setup, rasterization, vertex array caching, + * vertex/fragment programs/shaders, etc. + * + * + * \section AboutDoxygen About Doxygen + * + * If you're viewing this information as Doxygen-generated HTML you'll + * see the documentation index at the top of this page. + * + * The first line lists the Mesa source code modules. + * The second line lists the indexes available for viewing the documentation + * for each module. + * + * Selecting the <b>Main page</b> link will display a summary of the module + * (this page). + * + * Selecting <b>Data Structures</b> will list all C structures. + * + * Selecting the <b>File List</b> link will list all the source files in + * the module. + * Selecting a filename will show a list of all functions defined in that file. + * + * Selecting the <b>Data Fields</b> link will display a list of all + * documented structure members. + * + * Selecting the <b>Globals</b> link will display a list + * of all functions, structures, global variables and macros in the module. + * + */ + + +#include "glheader.h" +#include "mfeatures.h" +#include "imports.h" +#include "accum.h" +#include "api_exec.h" +#include "arrayobj.h" +#include "attrib.h" +#include "blend.h" +#include "buffers.h" +#include "bufferobj.h" +#include "context.h" +#include "cpuinfo.h" +#include "debug.h" +#include "depth.h" +#include "dlist.h" +#include "eval.h" +#include "extensions.h" +#include "fbobject.h" +#include "feedback.h" +#include "fog.h" +#include "formats.h" +#include "framebuffer.h" +#include "hint.h" +#include "hash.h" +#include "light.h" +#include "lines.h" +#include "macros.h" +#include "matrix.h" +#include "multisample.h" +#include "pixel.h" +#include "pixelstore.h" +#include "points.h" +#include "polygon.h" +#include "queryobj.h" +#include "syncobj.h" +#include "rastpos.h" +#include "remap.h" +#include "scissor.h" +#include "shared.h" +#include "shaderobj.h" +#include "simple_list.h" +#include "state.h" +#include "stencil.h" +#include "texcompress_s3tc.h" +#include "texstate.h" +#include "transformfeedback.h" +#include "mtypes.h" +#include "varray.h" +#include "version.h" +#include "viewport.h" +#include "vtxfmt.h" +#include "program/program.h" +#include "program/prog_print.h" +#if _HAVE_FULL_GL +#include "math/m_matrix.h" +#endif +#include "main/dispatch.h" /* for _gloffset_COUNT */ + +#ifdef USE_SPARC_ASM +#include "sparc/sparc.h" +#endif + +#include "glsl_parser_extras.h" +#include <stdbool.h> + + +#ifndef MESA_VERBOSE +int MESA_VERBOSE = 0; +#endif + +#ifndef MESA_DEBUG_FLAGS +int MESA_DEBUG_FLAGS = 0; +#endif + + +/* ubyte -> float conversion */ +GLfloat _mesa_ubyte_to_float_color_tab[256]; + + + +/** + * Swap buffers notification callback. + * + * \param ctx GL context. + * + * Called by window system just before swapping buffers. + * We have to finish any pending rendering. + */ +void +_mesa_notifySwapBuffers(struct gl_context *ctx) +{ + if (MESA_VERBOSE & VERBOSE_SWAPBUFFERS) + _mesa_debug(ctx, "SwapBuffers\n"); + FLUSH_CURRENT( ctx, 0 ); + if (ctx->Driver.Flush) { + ctx->Driver.Flush(ctx); + } +} + + +/**********************************************************************/ +/** \name GL Visual allocation/destruction */ +/**********************************************************************/ +/*@{*/ + +/** + * Allocates a struct gl_config structure and initializes it via + * _mesa_initialize_visual(). + * + * \param dbFlag double buffering + * \param stereoFlag stereo buffer + * \param depthBits requested bits per depth buffer value. Any value in [0, 32] + * is acceptable but the actual depth type will be GLushort or GLuint as + * needed. + * \param stencilBits requested minimum bits per stencil buffer value + * \param accumRedBits, accumGreenBits, accumBlueBits, accumAlphaBits number + * of bits per color component in accum buffer. + * \param indexBits number of bits per pixel if \p rgbFlag is GL_FALSE + * \param redBits number of bits per color component in frame buffer for RGB(A) + * mode. We always use 8 in core Mesa though. + * \param greenBits same as above. + * \param blueBits same as above. + * \param alphaBits same as above. + * \param numSamples not really used. + * + * \return pointer to new struct gl_config or NULL if requested parameters + * can't be met. + * + * \note Need to add params for level and numAuxBuffers (at least) + */ +struct gl_config * +_mesa_create_visual( GLboolean dbFlag, + GLboolean stereoFlag, + GLint redBits, + GLint greenBits, + GLint blueBits, + GLint alphaBits, + GLint depthBits, + GLint stencilBits, + GLint accumRedBits, + GLint accumGreenBits, + GLint accumBlueBits, + GLint accumAlphaBits, + GLint numSamples ) +{ + struct gl_config *vis = CALLOC_STRUCT(gl_config); + if (vis) { + if (!_mesa_initialize_visual(vis, dbFlag, stereoFlag, + redBits, greenBits, blueBits, alphaBits, + depthBits, stencilBits, + accumRedBits, accumGreenBits, + accumBlueBits, accumAlphaBits, + numSamples)) { + free(vis); + return NULL; + } + } + return vis; +} + + +/** + * Makes some sanity checks and fills in the fields of the struct + * gl_config object with the given parameters. If the caller needs to + * set additional fields, he should just probably init the whole + * gl_config object himself. + * + * \return GL_TRUE on success, or GL_FALSE on failure. + * + * \sa _mesa_create_visual() above for the parameter description. + */ +GLboolean +_mesa_initialize_visual( struct gl_config *vis, + GLboolean dbFlag, + GLboolean stereoFlag, + GLint redBits, + GLint greenBits, + GLint blueBits, + GLint alphaBits, + GLint depthBits, + GLint stencilBits, + GLint accumRedBits, + GLint accumGreenBits, + GLint accumBlueBits, + GLint accumAlphaBits, + GLint numSamples ) +{ + assert(vis); + + if (depthBits < 0 || depthBits > 32) { + return GL_FALSE; + } + if (stencilBits < 0 || stencilBits > STENCIL_BITS) { + return GL_FALSE; + } + assert(accumRedBits >= 0); + assert(accumGreenBits >= 0); + assert(accumBlueBits >= 0); + assert(accumAlphaBits >= 0); + + vis->rgbMode = GL_TRUE; + vis->doubleBufferMode = dbFlag; + vis->stereoMode = stereoFlag; + + vis->redBits = redBits; + vis->greenBits = greenBits; + vis->blueBits = blueBits; + vis->alphaBits = alphaBits; + vis->rgbBits = redBits + greenBits + blueBits; + + vis->indexBits = 0; + vis->depthBits = depthBits; + vis->stencilBits = stencilBits; + + vis->accumRedBits = accumRedBits; + vis->accumGreenBits = accumGreenBits; + vis->accumBlueBits = accumBlueBits; + vis->accumAlphaBits = accumAlphaBits; + + vis->haveAccumBuffer = accumRedBits > 0; + vis->haveDepthBuffer = depthBits > 0; + vis->haveStencilBuffer = stencilBits > 0; + + vis->numAuxBuffers = 0; + vis->level = 0; + vis->sampleBuffers = numSamples > 0 ? 1 : 0; + vis->samples = numSamples; + + return GL_TRUE; +} + + +/** + * Destroy a visual and free its memory. + * + * \param vis visual. + * + * Frees the visual structure. + */ +void +_mesa_destroy_visual( struct gl_config *vis ) +{ + free(vis); +} + +/*@}*/ + + +/**********************************************************************/ +/** \name Context allocation, initialization, destroying + * + * The purpose of the most initialization functions here is to provide the + * default state values according to the OpenGL specification. + */ +/**********************************************************************/ +/*@{*/ + + +/** + * This is lame. gdb only seems to recognize enum types that are + * actually used somewhere. We want to be able to print/use enum + * values such as TEXTURE_2D_INDEX in gdb. But we don't actually use + * the gl_texture_index type anywhere. Thus, this lame function. + */ +static void +dummy_enum_func(void) +{ + gl_buffer_index bi = BUFFER_FRONT_LEFT; + gl_face_index fi = FACE_POS_X; + gl_frag_attrib fa = FRAG_ATTRIB_WPOS; + gl_frag_result fr = FRAG_RESULT_DEPTH; + gl_texture_index ti = TEXTURE_2D_ARRAY_INDEX; + gl_vert_attrib va = VERT_ATTRIB_POS; + gl_vert_result vr = VERT_RESULT_HPOS; + gl_geom_attrib ga = GEOM_ATTRIB_POSITION; + gl_geom_result gr = GEOM_RESULT_POS; + + (void) bi; + (void) fi; + (void) fa; + (void) fr; + (void) ti; + (void) va; + (void) vr; + (void) ga; + (void) gr; +} + + +/** + * One-time initialization mutex lock. + * + * \sa Used by one_time_init(). + */ +_glthread_DECLARE_STATIC_MUTEX(OneTimeLock); + + + +/** + * Calls all the various one-time-init functions in Mesa. + * + * While holding a global mutex lock, calls several initialization functions, + * and sets the glapi callbacks if the \c MESA_DEBUG environment variable is + * defined. + * + * \sa _math_init(). + */ +static void +one_time_init( struct gl_context *ctx ) +{ + static GLbitfield api_init_mask = 0x0; + + _glthread_LOCK_MUTEX(OneTimeLock); + + /* truly one-time init */ + if (!api_init_mask) { + GLuint i; + + /* do some implementation tests */ + assert( sizeof(GLbyte) == 1 ); + assert( sizeof(GLubyte) == 1 ); + assert( sizeof(GLshort) == 2 ); + assert( sizeof(GLushort) == 2 ); + assert( sizeof(GLint) == 4 ); + assert( sizeof(GLuint) == 4 ); + + _mesa_get_cpu_features(); + + _mesa_init_sqrt_table(); + + /* context dependence is never a one-time thing... */ + _mesa_init_get_hash(ctx); + + for (i = 0; i < 256; i++) { + _mesa_ubyte_to_float_color_tab[i] = (float) i / 255.0F; + } + +#if defined(DEBUG) && defined(__DATE__) && defined(__TIME__) + if (MESA_VERBOSE != 0) { + _mesa_debug(ctx, "Mesa %s DEBUG build %s %s\n", + MESA_VERSION_STRING, __DATE__, __TIME__); + } +#endif + +#ifdef DEBUG + _mesa_test_formats(); +#endif + } + + /* per-API one-time init */ + if (!(api_init_mask & (1 << ctx->API))) { + /* + * This is fine as ES does not use the remap table, but it may not be + * future-proof. We cannot always initialize the remap table because + * when an app is linked to libGLES*, there are not enough dynamic + * entries. + */ + if (ctx->API == API_OPENGL) + _mesa_init_remap_table(); + } + + api_init_mask |= 1 << ctx->API; + + _glthread_UNLOCK_MUTEX(OneTimeLock); + + /* Hopefully atexit() is widely available. If not, we may need some + * #ifdef tests here. + */ + atexit(_mesa_destroy_shader_compiler); + + dummy_enum_func(); +} + + +/** + * Initialize fields of gl_current_attrib (aka ctx->Current.*) + */ +static void +_mesa_init_current(struct gl_context *ctx) +{ + GLuint i; + + /* Init all to (0,0,0,1) */ + for (i = 0; i < Elements(ctx->Current.Attrib); i++) { + ASSIGN_4V( ctx->Current.Attrib[i], 0.0, 0.0, 0.0, 1.0 ); + } + + /* redo special cases: */ + ASSIGN_4V( ctx->Current.Attrib[VERT_ATTRIB_WEIGHT], 1.0, 0.0, 0.0, 0.0 ); + ASSIGN_4V( ctx->Current.Attrib[VERT_ATTRIB_NORMAL], 0.0, 0.0, 1.0, 1.0 ); + ASSIGN_4V( ctx->Current.Attrib[VERT_ATTRIB_COLOR0], 1.0, 1.0, 1.0, 1.0 ); + ASSIGN_4V( ctx->Current.Attrib[VERT_ATTRIB_COLOR1], 0.0, 0.0, 0.0, 1.0 ); + ASSIGN_4V( ctx->Current.Attrib[VERT_ATTRIB_COLOR_INDEX], 1.0, 0.0, 0.0, 1.0 ); + ASSIGN_4V( ctx->Current.Attrib[VERT_ATTRIB_EDGEFLAG], 1.0, 0.0, 0.0, 1.0 ); +} + + +/** + * Init vertex/fragment/geometry program limits. + * Important: drivers should override these with actual limits. + */ +static void +init_program_limits(GLenum type, struct gl_program_constants *prog) +{ + prog->MaxInstructions = MAX_PROGRAM_INSTRUCTIONS; + prog->MaxAluInstructions = MAX_PROGRAM_INSTRUCTIONS; + prog->MaxTexInstructions = MAX_PROGRAM_INSTRUCTIONS; + prog->MaxTexIndirections = MAX_PROGRAM_INSTRUCTIONS; + prog->MaxTemps = MAX_PROGRAM_TEMPS; + prog->MaxEnvParams = MAX_PROGRAM_ENV_PARAMS; + prog->MaxLocalParams = MAX_PROGRAM_LOCAL_PARAMS; + prog->MaxAddressOffset = MAX_PROGRAM_LOCAL_PARAMS; + + switch (type) { + case GL_VERTEX_PROGRAM_ARB: + prog->MaxParameters = MAX_VERTEX_PROGRAM_PARAMS; + prog->MaxAttribs = MAX_NV_VERTEX_PROGRAM_INPUTS; + prog->MaxAddressRegs = MAX_VERTEX_PROGRAM_ADDRESS_REGS; + prog->MaxUniformComponents = 4 * MAX_UNIFORMS; + break; + case GL_FRAGMENT_PROGRAM_ARB: + prog->MaxParameters = MAX_NV_FRAGMENT_PROGRAM_PARAMS; + prog->MaxAttribs = MAX_NV_FRAGMENT_PROGRAM_INPUTS; + prog->MaxAddressRegs = MAX_FRAGMENT_PROGRAM_ADDRESS_REGS; + prog->MaxUniformComponents = 4 * MAX_UNIFORMS; + break; + case MESA_GEOMETRY_PROGRAM: + prog->MaxParameters = MAX_NV_VERTEX_PROGRAM_PARAMS; + prog->MaxAttribs = MAX_NV_VERTEX_PROGRAM_INPUTS; + prog->MaxAddressRegs = MAX_VERTEX_PROGRAM_ADDRESS_REGS; + prog->MaxUniformComponents = MAX_GEOMETRY_UNIFORM_COMPONENTS; + break; + default: + assert(0 && "Bad program type in init_program_limits()"); + } + + /* Set the native limits to zero. This implies that there is no native + * support for shaders. Let the drivers fill in the actual values. + */ + prog->MaxNativeInstructions = 0; + prog->MaxNativeAluInstructions = 0; + prog->MaxNativeTexInstructions = 0; + prog->MaxNativeTexIndirections = 0; + prog->MaxNativeAttribs = 0; + prog->MaxNativeTemps = 0; + prog->MaxNativeAddressRegs = 0; + prog->MaxNativeParameters = 0; + + /* Set GLSL datatype range/precision info assuming IEEE float values. + * Drivers should override these defaults as needed. + */ + prog->MediumFloat.RangeMin = 127; + prog->MediumFloat.RangeMax = 127; + prog->MediumFloat.Precision = 23; + prog->LowFloat = prog->HighFloat = prog->MediumFloat; + + /* Assume ints are stored as floats for now, since this is the least-common + * denominator. The OpenGL ES spec implies (page 132) that the precision + * of integer types should be 0. Practically speaking, IEEE + * single-precision floating point values can only store integers in the + * range [-0x01000000, 0x01000000] without loss of precision. + */ + prog->MediumInt.RangeMin = 24; + prog->MediumInt.RangeMax = 24; + prog->MediumInt.Precision = 0; + prog->LowInt = prog->HighInt = prog->MediumInt; +} + + +/** + * Initialize fields of gl_constants (aka ctx->Const.*). + * Use defaults from config.h. The device drivers will often override + * some of these values (such as number of texture units). + */ +static void +_mesa_init_constants(struct gl_context *ctx) +{ + assert(ctx); + + /* Constants, may be overriden (usually only reduced) by device drivers */ + ctx->Const.MaxTextureMbytes = MAX_TEXTURE_MBYTES; + ctx->Const.MaxTextureLevels = MAX_TEXTURE_LEVELS; + ctx->Const.Max3DTextureLevels = MAX_3D_TEXTURE_LEVELS; + ctx->Const.MaxCubeTextureLevels = MAX_CUBE_TEXTURE_LEVELS; + ctx->Const.MaxTextureRectSize = MAX_TEXTURE_RECT_SIZE; + ctx->Const.MaxArrayTextureLayers = MAX_ARRAY_TEXTURE_LAYERS; + ctx->Const.MaxTextureCoordUnits = MAX_TEXTURE_COORD_UNITS; + ctx->Const.MaxTextureImageUnits = MAX_TEXTURE_IMAGE_UNITS; + ctx->Const.MaxTextureUnits = MIN2(ctx->Const.MaxTextureCoordUnits, + ctx->Const.MaxTextureImageUnits); + ctx->Const.MaxTextureMaxAnisotropy = MAX_TEXTURE_MAX_ANISOTROPY; + ctx->Const.MaxTextureLodBias = MAX_TEXTURE_LOD_BIAS; + ctx->Const.MaxTextureBufferSize = 65536; + ctx->Const.MaxArrayLockSize = MAX_ARRAY_LOCK_SIZE; + ctx->Const.SubPixelBits = SUB_PIXEL_BITS; + ctx->Const.MinPointSize = MIN_POINT_SIZE; + ctx->Const.MaxPointSize = MAX_POINT_SIZE; + ctx->Const.MinPointSizeAA = MIN_POINT_SIZE; + ctx->Const.MaxPointSizeAA = MAX_POINT_SIZE; + ctx->Const.PointSizeGranularity = (GLfloat) POINT_SIZE_GRANULARITY; + ctx->Const.MinLineWidth = MIN_LINE_WIDTH; + ctx->Const.MaxLineWidth = MAX_LINE_WIDTH; + ctx->Const.MinLineWidthAA = MIN_LINE_WIDTH; + ctx->Const.MaxLineWidthAA = MAX_LINE_WIDTH; + ctx->Const.LineWidthGranularity = (GLfloat) LINE_WIDTH_GRANULARITY; + ctx->Const.MaxColorTableSize = MAX_COLOR_TABLE_SIZE; + ctx->Const.MaxClipPlanes = MAX_CLIP_PLANES; + ctx->Const.MaxLights = MAX_LIGHTS; + ctx->Const.MaxShininess = 128.0; + ctx->Const.MaxSpotExponent = 128.0; + ctx->Const.MaxViewportWidth = MAX_WIDTH; + ctx->Const.MaxViewportHeight = MAX_HEIGHT; +#if FEATURE_ARB_vertex_program + init_program_limits(GL_VERTEX_PROGRAM_ARB, &ctx->Const.VertexProgram); +#endif +#if FEATURE_ARB_fragment_program + init_program_limits(GL_FRAGMENT_PROGRAM_ARB, &ctx->Const.FragmentProgram); +#endif +#if FEATURE_ARB_geometry_shader4 + init_program_limits(MESA_GEOMETRY_PROGRAM, &ctx->Const.GeometryProgram); +#endif + ctx->Const.MaxProgramMatrices = MAX_PROGRAM_MATRICES; + ctx->Const.MaxProgramMatrixStackDepth = MAX_PROGRAM_MATRIX_STACK_DEPTH; + + /* CheckArrayBounds is overriden by drivers/x11 for X server */ + ctx->Const.CheckArrayBounds = GL_FALSE; + + /* GL_ARB_draw_buffers */ + ctx->Const.MaxDrawBuffers = MAX_DRAW_BUFFERS; + +#if FEATURE_EXT_framebuffer_object + ctx->Const.MaxColorAttachments = MAX_COLOR_ATTACHMENTS; + ctx->Const.MaxRenderbufferSize = MAX_WIDTH; +#endif + +#if FEATURE_ARB_vertex_shader + ctx->Const.MaxVertexTextureImageUnits = MAX_VERTEX_TEXTURE_IMAGE_UNITS; + ctx->Const.MaxCombinedTextureImageUnits = MAX_COMBINED_TEXTURE_IMAGE_UNITS; + ctx->Const.MaxVarying = MAX_VARYING; +#endif +#if FEATURE_ARB_geometry_shader4 + ctx->Const.MaxGeometryTextureImageUnits = MAX_GEOMETRY_TEXTURE_IMAGE_UNITS; + ctx->Const.MaxVertexVaryingComponents = MAX_VERTEX_VARYING_COMPONENTS; + ctx->Const.MaxGeometryVaryingComponents = MAX_GEOMETRY_VARYING_COMPONENTS; + ctx->Const.MaxGeometryOutputVertices = MAX_GEOMETRY_OUTPUT_VERTICES; + ctx->Const.MaxGeometryTotalOutputComponents = MAX_GEOMETRY_TOTAL_OUTPUT_COMPONENTS; +#endif + + /* Shading language version */ + if (ctx->API == API_OPENGL) { + ctx->Const.GLSLVersion = 120; + } + else if (ctx->API == API_OPENGLES2) { + ctx->Const.GLSLVersion = 100; + } + else if (ctx->API == API_OPENGLES) { + ctx->Const.GLSLVersion = 0; /* GLSL not supported */ + } + + /* GL_ARB_framebuffer_object */ + ctx->Const.MaxSamples = 0; + + /* GL_ARB_sync */ + ctx->Const.MaxServerWaitTimeout = (GLuint64) ~0; + + /* GL_ATI_envmap_bumpmap */ + ctx->Const.SupportedBumpUnits = SUPPORTED_ATI_BUMP_UNITS; + + /* GL_EXT_provoking_vertex */ + ctx->Const.QuadsFollowProvokingVertexConvention = GL_TRUE; + + /* GL_EXT_transform_feedback */ + ctx->Const.MaxTransformFeedbackSeparateAttribs = MAX_FEEDBACK_ATTRIBS; + ctx->Const.MaxTransformFeedbackSeparateComponents = 4 * MAX_FEEDBACK_ATTRIBS; + ctx->Const.MaxTransformFeedbackInterleavedComponents = 4 * MAX_FEEDBACK_ATTRIBS; + + /* GL 3.2: hard-coded for now: */ + ctx->Const.ProfileMask = GL_CONTEXT_COMPATIBILITY_PROFILE_BIT; + + /** GL_EXT_gpu_shader4 */ + ctx->Const.MinProgramTexelOffset = -8; + ctx->Const.MaxProgramTexelOffset = 7; +} + + +/** + * Do some sanity checks on the limits/constants for the given context. + * Only called the first time a context is bound. + */ +static void +check_context_limits(struct gl_context *ctx) +{ + /* check that we don't exceed the size of various bitfields */ + assert(VERT_RESULT_MAX <= + (8 * sizeof(ctx->VertexProgram._Current->Base.OutputsWritten))); + assert(FRAG_ATTRIB_MAX <= + (8 * sizeof(ctx->FragmentProgram._Current->Base.InputsRead))); + + assert(MAX_COMBINED_TEXTURE_IMAGE_UNITS <= 8 * sizeof(GLbitfield)); + + /* shader-related checks */ + assert(ctx->Const.FragmentProgram.MaxLocalParams <= MAX_PROGRAM_LOCAL_PARAMS); + assert(ctx->Const.VertexProgram.MaxLocalParams <= MAX_PROGRAM_LOCAL_PARAMS); + + assert(MAX_NV_FRAGMENT_PROGRAM_TEMPS <= MAX_PROGRAM_TEMPS); + assert(MAX_NV_VERTEX_PROGRAM_TEMPS <= MAX_PROGRAM_TEMPS); + assert(MAX_NV_VERTEX_PROGRAM_INPUTS <= VERT_ATTRIB_MAX); + assert(MAX_NV_VERTEX_PROGRAM_OUTPUTS <= VERT_RESULT_MAX); + + /* Texture unit checks */ + assert(ctx->Const.MaxTextureImageUnits > 0); + assert(ctx->Const.MaxTextureImageUnits <= MAX_TEXTURE_IMAGE_UNITS); + assert(ctx->Const.MaxTextureCoordUnits > 0); + assert(ctx->Const.MaxTextureCoordUnits <= MAX_TEXTURE_COORD_UNITS); + assert(ctx->Const.MaxTextureUnits > 0); + assert(ctx->Const.MaxTextureUnits <= MAX_TEXTURE_IMAGE_UNITS); + assert(ctx->Const.MaxTextureUnits <= MAX_TEXTURE_COORD_UNITS); + assert(ctx->Const.MaxTextureUnits == MIN2(ctx->Const.MaxTextureImageUnits, + ctx->Const.MaxTextureCoordUnits)); + assert(ctx->Const.MaxCombinedTextureImageUnits > 0); + assert(ctx->Const.MaxCombinedTextureImageUnits <= MAX_COMBINED_TEXTURE_IMAGE_UNITS); + assert(ctx->Const.MaxTextureCoordUnits <= MAX_COMBINED_TEXTURE_IMAGE_UNITS); + /* number of coord units cannot be greater than number of image units */ + assert(ctx->Const.MaxTextureCoordUnits <= ctx->Const.MaxTextureImageUnits); + + + /* Texture size checks */ + assert(ctx->Const.MaxTextureLevels <= MAX_TEXTURE_LEVELS); + assert(ctx->Const.Max3DTextureLevels <= MAX_3D_TEXTURE_LEVELS); + assert(ctx->Const.MaxCubeTextureLevels <= MAX_CUBE_TEXTURE_LEVELS); + assert(ctx->Const.MaxTextureRectSize <= MAX_TEXTURE_RECT_SIZE); + + /* make sure largest texture image is <= MAX_WIDTH in size */ + assert((1 << (ctx->Const.MaxTextureLevels - 1)) <= MAX_WIDTH); + assert((1 << (ctx->Const.MaxCubeTextureLevels - 1)) <= MAX_WIDTH); + assert((1 << (ctx->Const.Max3DTextureLevels - 1)) <= MAX_WIDTH); + + /* Texture level checks */ + assert(MAX_TEXTURE_LEVELS >= MAX_3D_TEXTURE_LEVELS); + assert(MAX_TEXTURE_LEVELS >= MAX_CUBE_TEXTURE_LEVELS); + + /* Max texture size should be <= max viewport size (render to texture) */ + assert((1 << (MAX_TEXTURE_LEVELS - 1)) <= MAX_WIDTH); + + assert(ctx->Const.MaxViewportWidth <= MAX_WIDTH); + assert(ctx->Const.MaxViewportHeight <= MAX_WIDTH); + + assert(ctx->Const.MaxDrawBuffers <= MAX_DRAW_BUFFERS); + + /* if this fails, add more enum values to gl_buffer_index */ + assert(BUFFER_COLOR0 + MAX_DRAW_BUFFERS <= BUFFER_COUNT); + + /* XXX probably add more tests */ +} + + +/** + * Initialize the attribute groups in a GL context. + * + * \param ctx GL context. + * + * Initializes all the attributes, calling the respective <tt>init*</tt> + * functions for the more complex data structures. + */ +static GLboolean +init_attrib_groups(struct gl_context *ctx) +{ + assert(ctx); + + /* Constants */ + _mesa_init_constants( ctx ); + + /* Extensions */ + _mesa_init_extensions( ctx ); + + /* Attribute Groups */ + _mesa_init_accum( ctx ); + _mesa_init_attrib( ctx ); + _mesa_init_buffer_objects( ctx ); + _mesa_init_color( ctx ); + _mesa_init_current( ctx ); + _mesa_init_depth( ctx ); + _mesa_init_debug( ctx ); + _mesa_init_display_list( ctx ); + _mesa_init_eval( ctx ); + _mesa_init_fbobjects( ctx ); + _mesa_init_feedback( ctx ); + _mesa_init_fog( ctx ); + _mesa_init_hint( ctx ); + _mesa_init_line( ctx ); + _mesa_init_lighting( ctx ); + _mesa_init_matrix( ctx ); + _mesa_init_multisample( ctx ); + _mesa_init_pixel( ctx ); + _mesa_init_pixelstore( ctx ); + _mesa_init_point( ctx ); + _mesa_init_polygon( ctx ); + _mesa_init_program( ctx ); + _mesa_init_queryobj( ctx ); + _mesa_init_sync( ctx ); + _mesa_init_rastpos( ctx ); + _mesa_init_scissor( ctx ); + _mesa_init_shader_state( ctx ); + _mesa_init_stencil( ctx ); + _mesa_init_transform( ctx ); + _mesa_init_transform_feedback( ctx ); + _mesa_init_varray( ctx ); + _mesa_init_viewport( ctx ); + + if (!_mesa_init_texture( ctx )) + return GL_FALSE; + + _mesa_init_texture_s3tc( ctx ); + + /* Miscellaneous */ + ctx->NewState = _NEW_ALL; + ctx->ErrorValue = (GLenum) GL_NO_ERROR; + ctx->varying_vp_inputs = ~0; + + return GL_TRUE; +} + + +/** + * Update default objects in a GL context with respect to shared state. + * + * \param ctx GL context. + * + * Removes references to old default objects, (texture objects, program + * objects, etc.) and changes to reference those from the current shared + * state. + */ +static GLboolean +update_default_objects(struct gl_context *ctx) +{ + assert(ctx); + + _mesa_update_default_objects_program(ctx); + _mesa_update_default_objects_texture(ctx); + _mesa_update_default_objects_buffer_objects(ctx); + + return GL_TRUE; +} + + +/** + * This is the default function we plug into all dispatch table slots + * This helps prevents a segfault when someone calls a GL function without + * first checking if the extension's supported. + */ +static int +generic_nop(void) +{ + _mesa_warning(NULL, "User called no-op dispatch function (an unsupported extension function?)"); + return 0; +} + + +/** + * Allocate and initialize a new dispatch table. + */ +struct _glapi_table * +_mesa_alloc_dispatch_table(int size) +{ + /* Find the larger of Mesa's dispatch table and libGL's dispatch table. + * In practice, this'll be the same for stand-alone Mesa. But for DRI + * Mesa we do this to accomodate different versions of libGL and various + * DRI drivers. + */ + GLint numEntries = MAX2(_glapi_get_dispatch_table_size(), _gloffset_COUNT); + struct _glapi_table *table; + + /* should never happen, but just in case */ + numEntries = MAX2(numEntries, size); + + table = (struct _glapi_table *) malloc(numEntries * sizeof(_glapi_proc)); + if (table) { + _glapi_proc *entry = (_glapi_proc *) table; + GLint i; + for (i = 0; i < numEntries; i++) { + entry[i] = (_glapi_proc) generic_nop; + } + } + return table; +} + + +/** + * Initialize a struct gl_context struct (rendering context). + * + * This includes allocating all the other structs and arrays which hang off of + * the context by pointers. + * Note that the driver needs to pass in its dd_function_table here since + * we need to at least call driverFunctions->NewTextureObject to create the + * default texture objects. + * + * Called by _mesa_create_context(). + * + * Performs the imports and exports callback tables initialization, and + * miscellaneous one-time initializations. If no shared context is supplied one + * is allocated, and increase its reference count. Setups the GL API dispatch + * tables. Initialize the TNL module. Sets the maximum Z buffer depth. + * Finally queries the \c MESA_DEBUG and \c MESA_VERBOSE environment variables + * for debug flags. + * + * \param ctx the context to initialize + * \param api the GL API type to create the context for + * \param visual describes the visual attributes for this context + * \param share_list points to context to share textures, display lists, + * etc with, or NULL + * \param driverFunctions table of device driver functions for this context + * to use + * \param driverContext pointer to driver-specific context data + */ +GLboolean +_mesa_initialize_context(struct gl_context *ctx, + gl_api api, + const struct gl_config *visual, + struct gl_context *share_list, + const struct dd_function_table *driverFunctions, + void *driverContext) +{ + struct gl_shared_state *shared; + int i; + + /*ASSERT(driverContext);*/ + assert(driverFunctions->NewTextureObject); + assert(driverFunctions->FreeTexImageData); + + ctx->API = api; + ctx->Visual = *visual; + ctx->DrawBuffer = NULL; + ctx->ReadBuffer = NULL; + ctx->WinSysDrawBuffer = NULL; + ctx->WinSysReadBuffer = NULL; + + /* misc one-time initializations */ + one_time_init(ctx); + + /* Plug in driver functions and context pointer here. + * This is important because when we call alloc_shared_state() below + * we'll call ctx->Driver.NewTextureObject() to create the default + * textures. + */ + ctx->Driver = *driverFunctions; + ctx->DriverCtx = driverContext; + + if (share_list) { + /* share state with another context */ + shared = share_list->Shared; + } + else { + /* allocate new, unshared state */ + shared = _mesa_alloc_shared_state(ctx); + if (!shared) + return GL_FALSE; + } + + _glthread_LOCK_MUTEX(shared->Mutex); + ctx->Shared = shared; + shared->RefCount++; + _glthread_UNLOCK_MUTEX(shared->Mutex); + + if (!init_attrib_groups( ctx )) { + _mesa_release_shared_state(ctx, ctx->Shared); + return GL_FALSE; + } + +#if FEATURE_dispatch + /* setup the API dispatch tables */ + switch (ctx->API) { +#if FEATURE_GL + case API_OPENGL: + ctx->Exec = _mesa_create_exec_table(); + break; +#endif +#if FEATURE_ES1 + case API_OPENGLES: + ctx->Exec = _mesa_create_exec_table_es1(); + break; +#endif +#if FEATURE_ES2 + case API_OPENGLES2: + ctx->Exec = _mesa_create_exec_table_es2(); + break; +#endif + default: + _mesa_problem(ctx, "unknown or unsupported API"); + break; + } + + if (!ctx->Exec) { + _mesa_release_shared_state(ctx, ctx->Shared); + return GL_FALSE; + } +#endif + ctx->CurrentDispatch = ctx->Exec; + + ctx->FragmentProgram._MaintainTexEnvProgram + = (_mesa_getenv("MESA_TEX_PROG") != NULL); + + ctx->VertexProgram._MaintainTnlProgram + = (_mesa_getenv("MESA_TNL_PROG") != NULL); + if (ctx->VertexProgram._MaintainTnlProgram) { + /* this is required... */ + ctx->FragmentProgram._MaintainTexEnvProgram = GL_TRUE; + } + + /* Mesa core handles all the formats that mesa core knows about. + * Drivers will want to override this list with just the formats + * they can handle, and confirm that appropriate fallbacks exist in + * _mesa_choose_tex_format(). + */ + memset(&ctx->TextureFormatSupported, GL_TRUE, + sizeof(ctx->TextureFormatSupported)); + + switch (ctx->API) { + case API_OPENGL: +#if FEATURE_dlist + ctx->Save = _mesa_create_save_table(); + if (!ctx->Save) { + _mesa_release_shared_state(ctx, ctx->Shared); + free(ctx->Exec); + return GL_FALSE; + } + + _mesa_install_save_vtxfmt( ctx, &ctx->ListState.ListVtxfmt ); +#endif + break; + case API_OPENGLES: + /** + * GL_OES_texture_cube_map says + * "Initially all texture generation modes are set to REFLECTION_MAP_OES" + */ + for (i = 0; i < MAX_TEXTURE_UNITS; i++) { + struct gl_texture_unit *texUnit = &ctx->Texture.Unit[i]; + texUnit->GenS.Mode = GL_REFLECTION_MAP_NV; + texUnit->GenT.Mode = GL_REFLECTION_MAP_NV; + texUnit->GenR.Mode = GL_REFLECTION_MAP_NV; + texUnit->GenS._ModeBit = TEXGEN_REFLECTION_MAP_NV; + texUnit->GenT._ModeBit = TEXGEN_REFLECTION_MAP_NV; + texUnit->GenR._ModeBit = TEXGEN_REFLECTION_MAP_NV; + } + break; + case API_OPENGLES2: + ctx->FragmentProgram._MaintainTexEnvProgram = GL_TRUE; + ctx->VertexProgram._MaintainTnlProgram = GL_TRUE; + ctx->Point.PointSprite = GL_TRUE; /* always on for ES 2.x */ + break; + } + + ctx->FirstTimeCurrent = GL_TRUE; + + return GL_TRUE; +} + + +/** + * Allocate and initialize a struct gl_context structure. + * Note that the driver needs to pass in its dd_function_table here since + * we need to at least call driverFunctions->NewTextureObject to initialize + * the rendering context. + * + * \param api the GL API type to create the context for + * \param visual a struct gl_config pointer (we copy the struct contents) + * \param share_list another context to share display lists with or NULL + * \param driverFunctions points to the dd_function_table into which the + * driver has plugged in all its special functions. + * \param driverContext points to the device driver's private context state + * + * \return pointer to a new __struct gl_contextRec or NULL if error. + */ +struct gl_context * +_mesa_create_context(gl_api api, + const struct gl_config *visual, + struct gl_context *share_list, + const struct dd_function_table *driverFunctions, + void *driverContext) +{ + struct gl_context *ctx; + + ASSERT(visual); + /*ASSERT(driverContext);*/ + + ctx = (struct gl_context *) calloc(1, sizeof(struct gl_context)); + if (!ctx) + return NULL; + + if (_mesa_initialize_context(ctx, api, visual, share_list, + driverFunctions, driverContext)) { + return ctx; + } + else { + free(ctx); + return NULL; + } +} + + +/** + * Free the data associated with the given context. + * + * But doesn't free the struct gl_context struct itself. + * + * \sa _mesa_initialize_context() and init_attrib_groups(). + */ +void +_mesa_free_context_data( struct gl_context *ctx ) +{ + if (!_mesa_get_current_context()){ + /* No current context, but we may need one in order to delete + * texture objs, etc. So temporarily bind the context now. + */ + _mesa_make_current(ctx, NULL, NULL); + } + + /* unreference WinSysDraw/Read buffers */ + _mesa_reference_framebuffer(&ctx->WinSysDrawBuffer, NULL); + _mesa_reference_framebuffer(&ctx->WinSysReadBuffer, NULL); + _mesa_reference_framebuffer(&ctx->DrawBuffer, NULL); + _mesa_reference_framebuffer(&ctx->ReadBuffer, NULL); + + _mesa_reference_vertprog(ctx, &ctx->VertexProgram.Current, NULL); + _mesa_reference_vertprog(ctx, &ctx->VertexProgram._Current, NULL); + _mesa_reference_vertprog(ctx, &ctx->VertexProgram._TnlProgram, NULL); + + _mesa_reference_fragprog(ctx, &ctx->FragmentProgram.Current, NULL); + _mesa_reference_fragprog(ctx, &ctx->FragmentProgram._Current, NULL); + _mesa_reference_fragprog(ctx, &ctx->FragmentProgram._TexEnvProgram, NULL); + + _mesa_free_attrib_data(ctx); + _mesa_free_buffer_objects(ctx); + _mesa_free_lighting_data( ctx ); + _mesa_free_eval_data( ctx ); + _mesa_free_texture_data( ctx ); + _mesa_free_matrix_data( ctx ); + _mesa_free_viewport_data( ctx ); + _mesa_free_program_data(ctx); + _mesa_free_shader_state(ctx); + _mesa_free_queryobj_data(ctx); + _mesa_free_sync_data(ctx); + _mesa_free_varray_data(ctx); + _mesa_free_transform_feedback(ctx); + + _mesa_delete_array_object(ctx, ctx->Array.DefaultArrayObj); + +#if FEATURE_ARB_pixel_buffer_object + _mesa_reference_buffer_object(ctx, &ctx->Pack.BufferObj, NULL); + _mesa_reference_buffer_object(ctx, &ctx->Unpack.BufferObj, NULL); + _mesa_reference_buffer_object(ctx, &ctx->DefaultPacking.BufferObj, NULL); +#endif + +#if FEATURE_ARB_vertex_buffer_object + _mesa_reference_buffer_object(ctx, &ctx->Array.ArrayBufferObj, NULL); + _mesa_reference_buffer_object(ctx, &ctx->Array.ElementArrayBufferObj, NULL); +#endif + + /* free dispatch tables */ + free(ctx->Exec); + free(ctx->Save); + + /* Shared context state (display lists, textures, etc) */ + _mesa_release_shared_state( ctx, ctx->Shared ); + + /* needs to be after freeing shared state */ + _mesa_free_display_list_data(ctx); + + if (ctx->Extensions.String) + free((void *) ctx->Extensions.String); + + if (ctx->VersionString) + free(ctx->VersionString); + + /* unbind the context if it's currently bound */ + if (ctx == _mesa_get_current_context()) { + _mesa_make_current(NULL, NULL, NULL); + } +} + + +/** + * Destroy a struct gl_context structure. + * + * \param ctx GL context. + * + * Calls _mesa_free_context_data() and frees the gl_context object itself. + */ +void +_mesa_destroy_context( struct gl_context *ctx ) +{ + if (ctx) { + _mesa_free_context_data(ctx); + free( (void *) ctx ); + } +} + + +#if _HAVE_FULL_GL +/** + * Copy attribute groups from one context to another. + * + * \param src source context + * \param dst destination context + * \param mask bitwise OR of GL_*_BIT flags + * + * According to the bits specified in \p mask, copies the corresponding + * attributes from \p src into \p dst. For many of the attributes a simple \c + * memcpy is not enough due to the existence of internal pointers in their data + * structures. + */ +void +_mesa_copy_context( const struct gl_context *src, struct gl_context *dst, + GLuint mask ) +{ + if (mask & GL_ACCUM_BUFFER_BIT) { + /* OK to memcpy */ + dst->Accum = src->Accum; + } + if (mask & GL_COLOR_BUFFER_BIT) { + /* OK to memcpy */ + dst->Color = src->Color; + } + if (mask & GL_CURRENT_BIT) { + /* OK to memcpy */ + dst->Current = src->Current; + } + if (mask & GL_DEPTH_BUFFER_BIT) { + /* OK to memcpy */ + dst->Depth = src->Depth; + } + if (mask & GL_ENABLE_BIT) { + /* no op */ + } + if (mask & GL_EVAL_BIT) { + /* OK to memcpy */ + dst->Eval = src->Eval; + } + if (mask & GL_FOG_BIT) { + /* OK to memcpy */ + dst->Fog = src->Fog; + } + if (mask & GL_HINT_BIT) { + /* OK to memcpy */ + dst->Hint = src->Hint; + } + if (mask & GL_LIGHTING_BIT) { + GLuint i; + /* begin with memcpy */ + dst->Light = src->Light; + /* fixup linked lists to prevent pointer insanity */ + make_empty_list( &(dst->Light.EnabledList) ); + for (i = 0; i < MAX_LIGHTS; i++) { + if (dst->Light.Light[i].Enabled) { + insert_at_tail(&(dst->Light.EnabledList), &(dst->Light.Light[i])); + } + } + } + if (mask & GL_LINE_BIT) { + /* OK to memcpy */ + dst->Line = src->Line; + } + if (mask & GL_LIST_BIT) { + /* OK to memcpy */ + dst->List = src->List; + } + if (mask & GL_PIXEL_MODE_BIT) { + /* OK to memcpy */ + dst->Pixel = src->Pixel; + } + if (mask & GL_POINT_BIT) { + /* OK to memcpy */ + dst->Point = src->Point; + } + if (mask & GL_POLYGON_BIT) { + /* OK to memcpy */ + dst->Polygon = src->Polygon; + } + if (mask & GL_POLYGON_STIPPLE_BIT) { + /* Use loop instead of memcpy due to problem with Portland Group's + * C compiler. Reported by John Stone. + */ + GLuint i; + for (i = 0; i < 32; i++) { + dst->PolygonStipple[i] = src->PolygonStipple[i]; + } + } + if (mask & GL_SCISSOR_BIT) { + /* OK to memcpy */ + dst->Scissor = src->Scissor; + } + if (mask & GL_STENCIL_BUFFER_BIT) { + /* OK to memcpy */ + dst->Stencil = src->Stencil; + } + if (mask & GL_TEXTURE_BIT) { + /* Cannot memcpy because of pointers */ + _mesa_copy_texture_state(src, dst); + } + if (mask & GL_TRANSFORM_BIT) { + /* OK to memcpy */ + dst->Transform = src->Transform; + } + if (mask & GL_VIEWPORT_BIT) { + /* Cannot use memcpy, because of pointers in GLmatrix _WindowMap */ + dst->Viewport.X = src->Viewport.X; + dst->Viewport.Y = src->Viewport.Y; + dst->Viewport.Width = src->Viewport.Width; + dst->Viewport.Height = src->Viewport.Height; + dst->Viewport.Near = src->Viewport.Near; + dst->Viewport.Far = src->Viewport.Far; + _math_matrix_copy(&dst->Viewport._WindowMap, &src->Viewport._WindowMap); + } + + /* XXX FIXME: Call callbacks? + */ + dst->NewState = _NEW_ALL; +} +#endif + + +/** + * Check if the given context can render into the given framebuffer + * by checking visual attributes. + * + * Most of these tests could go away because Mesa is now pretty flexible + * in terms of mixing rendering contexts with framebuffers. As long + * as RGB vs. CI mode agree, we're probably good. + * + * \return GL_TRUE if compatible, GL_FALSE otherwise. + */ +static GLboolean +check_compatible(const struct gl_context *ctx, + const struct gl_framebuffer *buffer) +{ + const struct gl_config *ctxvis = &ctx->Visual; + const struct gl_config *bufvis = &buffer->Visual; + + if (buffer == _mesa_get_incomplete_framebuffer()) + return GL_TRUE; + +#if 0 + /* disabling this fixes the fgl_glxgears pbuffer demo */ + if (ctxvis->doubleBufferMode && !bufvis->doubleBufferMode) + return GL_FALSE; +#endif + if (ctxvis->stereoMode && !bufvis->stereoMode) + return GL_FALSE; + if (ctxvis->haveAccumBuffer && !bufvis->haveAccumBuffer) + return GL_FALSE; + if (ctxvis->haveDepthBuffer && !bufvis->haveDepthBuffer) + return GL_FALSE; + if (ctxvis->haveStencilBuffer && !bufvis->haveStencilBuffer) + return GL_FALSE; + if (ctxvis->redMask && ctxvis->redMask != bufvis->redMask) + return GL_FALSE; + if (ctxvis->greenMask && ctxvis->greenMask != bufvis->greenMask) + return GL_FALSE; + if (ctxvis->blueMask && ctxvis->blueMask != bufvis->blueMask) + return GL_FALSE; +#if 0 + /* disabled (see bug 11161) */ + if (ctxvis->depthBits && ctxvis->depthBits != bufvis->depthBits) + return GL_FALSE; +#endif + if (ctxvis->stencilBits && ctxvis->stencilBits != bufvis->stencilBits) + return GL_FALSE; + + return GL_TRUE; +} + + +/** + * Do one-time initialization for the given framebuffer. Specifically, + * ask the driver for the window's current size and update the framebuffer + * object to match. + * Really, the device driver should totally take care of this. + */ +static void +initialize_framebuffer_size(struct gl_context *ctx, struct gl_framebuffer *fb) +{ + GLuint width, height; + if (ctx->Driver.GetBufferSize) { + ctx->Driver.GetBufferSize(fb, &width, &height); + if (ctx->Driver.ResizeBuffers) + ctx->Driver.ResizeBuffers(ctx, fb, width, height); + fb->Initialized = GL_TRUE; + } +} + + +/** + * Check if the viewport/scissor size has not yet been initialized. + * Initialize the size if the given width and height are non-zero. + */ +void +_mesa_check_init_viewport(struct gl_context *ctx, GLuint width, GLuint height) +{ + if (!ctx->ViewportInitialized && width > 0 && height > 0) { + /* Note: set flag here, before calling _mesa_set_viewport(), to prevent + * potential infinite recursion. + */ + ctx->ViewportInitialized = GL_TRUE; + _mesa_set_viewport(ctx, 0, 0, width, height); + _mesa_set_scissor(ctx, 0, 0, width, height); + } +} + + +/** + * Bind the given context to the given drawBuffer and readBuffer and + * make it the current context for the calling thread. + * We'll render into the drawBuffer and read pixels from the + * readBuffer (i.e. glRead/CopyPixels, glCopyTexImage, etc). + * + * We check that the context's and framebuffer's visuals are compatible + * and return immediately if they're not. + * + * \param newCtx the new GL context. If NULL then there will be no current GL + * context. + * \param drawBuffer the drawing framebuffer + * \param readBuffer the reading framebuffer + */ +GLboolean +_mesa_make_current( struct gl_context *newCtx, + struct gl_framebuffer *drawBuffer, + struct gl_framebuffer *readBuffer ) +{ + GET_CURRENT_CONTEXT(curCtx); + + if (MESA_VERBOSE & VERBOSE_API) + _mesa_debug(newCtx, "_mesa_make_current()\n"); + + /* Check that the context's and framebuffer's visuals are compatible. + */ + if (newCtx && drawBuffer && newCtx->WinSysDrawBuffer != drawBuffer) { + if (!check_compatible(newCtx, drawBuffer)) { + _mesa_warning(newCtx, + "MakeCurrent: incompatible visuals for context and drawbuffer"); + return GL_FALSE; + } + } + if (newCtx && readBuffer && newCtx->WinSysReadBuffer != readBuffer) { + if (!check_compatible(newCtx, readBuffer)) { + _mesa_warning(newCtx, + "MakeCurrent: incompatible visuals for context and readbuffer"); + return GL_FALSE; + } + } + + if (curCtx && + (curCtx->WinSysDrawBuffer || curCtx->WinSysReadBuffer) && /* make sure this context is valid for flushing */ + curCtx != newCtx) + _mesa_flush(curCtx); + + /* We used to call _glapi_check_multithread() here. Now do it in drivers */ + _glapi_set_context((void *) newCtx); + ASSERT(_mesa_get_current_context() == newCtx); + + if (!newCtx) { + _glapi_set_dispatch(NULL); /* none current */ + } + else { + _glapi_set_dispatch(newCtx->CurrentDispatch); + + if (drawBuffer && readBuffer) { + /* TODO: check if newCtx and buffer's visual match??? */ + + ASSERT(drawBuffer->Name == 0); + ASSERT(readBuffer->Name == 0); + _mesa_reference_framebuffer(&newCtx->WinSysDrawBuffer, drawBuffer); + _mesa_reference_framebuffer(&newCtx->WinSysReadBuffer, readBuffer); + + /* + * Only set the context's Draw/ReadBuffer fields if they're NULL + * or not bound to a user-created FBO. + */ + if (!newCtx->DrawBuffer || newCtx->DrawBuffer->Name == 0) { + /* KW: merge conflict here, revisit. + */ + /* fix up the fb fields - these will end up wrong otherwise + * if the DRIdrawable changes, and everything relies on them. + * This is a bit messy (same as needed in _mesa_BindFramebufferEXT) + */ + unsigned int i; + GLenum buffers[MAX_DRAW_BUFFERS]; + + _mesa_reference_framebuffer(&newCtx->DrawBuffer, drawBuffer); + + for(i = 0; i < newCtx->Const.MaxDrawBuffers; i++) { + buffers[i] = newCtx->Color.DrawBuffer[i]; + } + + _mesa_drawbuffers(newCtx, newCtx->Const.MaxDrawBuffers, + buffers, NULL); + } + if (!newCtx->ReadBuffer || newCtx->ReadBuffer->Name == 0) { + _mesa_reference_framebuffer(&newCtx->ReadBuffer, readBuffer); + } + + /* XXX only set this flag if we're really changing the draw/read + * framebuffer bindings. + */ + newCtx->NewState |= _NEW_BUFFERS; + +#if 1 + /* We want to get rid of these lines: */ + +#if _HAVE_FULL_GL + if (!drawBuffer->Initialized) { + initialize_framebuffer_size(newCtx, drawBuffer); + } + if (readBuffer != drawBuffer && !readBuffer->Initialized) { + initialize_framebuffer_size(newCtx, readBuffer); + } + + _mesa_resizebuffers(newCtx); +#endif + +#else + /* We want the drawBuffer and readBuffer to be initialized by + * the driver. + * This generally means the Width and Height match the actual + * window size and the renderbuffers (both hardware and software + * based) are allocated to match. The later can generally be + * done with a call to _mesa_resize_framebuffer(). + * + * It's theoretically possible for a buffer to have zero width + * or height, but for now, assert check that the driver did what's + * expected of it. + */ + ASSERT(drawBuffer->Width > 0); + ASSERT(drawBuffer->Height > 0); +#endif + + if (drawBuffer) { + _mesa_check_init_viewport(newCtx, + drawBuffer->Width, drawBuffer->Height); + } + } + + if (newCtx->FirstTimeCurrent) { + _mesa_compute_version(newCtx); + + newCtx->Extensions.String = _mesa_make_extension_string(newCtx); + + check_context_limits(newCtx); + + /* We can use this to help debug user's problems. Tell them to set + * the MESA_INFO env variable before running their app. Then the + * first time each context is made current we'll print some useful + * information. + */ + if (_mesa_getenv("MESA_INFO")) { + _mesa_print_info(); + } + + newCtx->FirstTimeCurrent = GL_FALSE; + } + } + + return GL_TRUE; +} + + +/** + * Make context 'ctx' share the display lists, textures and programs + * that are associated with 'ctxToShare'. + * Any display lists, textures or programs associated with 'ctx' will + * be deleted if nobody else is sharing them. + */ +GLboolean +_mesa_share_state(struct gl_context *ctx, struct gl_context *ctxToShare) +{ + if (ctx && ctxToShare && ctx->Shared && ctxToShare->Shared) { + struct gl_shared_state *oldSharedState = ctx->Shared; + + ctx->Shared = ctxToShare->Shared; + + _glthread_LOCK_MUTEX(ctx->Shared->Mutex); + ctx->Shared->RefCount++; + _glthread_UNLOCK_MUTEX(ctx->Shared->Mutex); + + update_default_objects(ctx); + + _mesa_release_shared_state(ctx, oldSharedState); + + return GL_TRUE; + } + else { + return GL_FALSE; + } +} + + + +/** + * \return pointer to the current GL context for this thread. + * + * Calls _glapi_get_context(). This isn't the fastest way to get the current + * context. If you need speed, see the #GET_CURRENT_CONTEXT macro in + * context.h. + */ +struct gl_context * +_mesa_get_current_context( void ) +{ + return (struct gl_context *) _glapi_get_context(); +} + + +/** + * Get context's current API dispatch table. + * + * It'll either be the immediate-mode execute dispatcher or the display list + * compile dispatcher. + * + * \param ctx GL context. + * + * \return pointer to dispatch_table. + * + * Simply returns __struct gl_contextRec::CurrentDispatch. + */ +struct _glapi_table * +_mesa_get_dispatch(struct gl_context *ctx) +{ + return ctx->CurrentDispatch; +} + +/*@}*/ + + +/**********************************************************************/ +/** \name Miscellaneous functions */ +/**********************************************************************/ +/*@{*/ + +/** + * Record an error. + * + * \param ctx GL context. + * \param error error code. + * + * Records the given error code and call the driver's dd_function_table::Error + * function if defined. + * + * \sa + * This is called via _mesa_error(). + */ +void +_mesa_record_error(struct gl_context *ctx, GLenum error) +{ + if (!ctx) + return; + + if (ctx->ErrorValue == GL_NO_ERROR) { + ctx->ErrorValue = error; + } + + /* Call device driver's error handler, if any. This is used on the Mac. */ + if (ctx->Driver.Error) { + ctx->Driver.Error(ctx); + } +} + + +/** + * Flush commands and wait for completion. + */ +void +_mesa_finish(struct gl_context *ctx) +{ + FLUSH_CURRENT( ctx, 0 ); + if (ctx->Driver.Finish) { + ctx->Driver.Finish(ctx); + } +} + + +/** + * Flush commands. + */ +void +_mesa_flush(struct gl_context *ctx) +{ + FLUSH_CURRENT( ctx, 0 ); + if (ctx->Driver.Flush) { + ctx->Driver.Flush(ctx); + } +} + + + +/** + * Execute glFinish(). + * + * Calls the #ASSERT_OUTSIDE_BEGIN_END_AND_FLUSH macro and the + * dd_function_table::Finish driver callback, if not NULL. + */ +void GLAPIENTRY +_mesa_Finish(void) +{ + GET_CURRENT_CONTEXT(ctx); + ASSERT_OUTSIDE_BEGIN_END_AND_FLUSH(ctx); + _mesa_finish(ctx); +} + + +/** + * Execute glFlush(). + * + * Calls the #ASSERT_OUTSIDE_BEGIN_END_AND_FLUSH macro and the + * dd_function_table::Flush driver callback, if not NULL. + */ +void GLAPIENTRY +_mesa_Flush(void) +{ + GET_CURRENT_CONTEXT(ctx); + ASSERT_OUTSIDE_BEGIN_END_AND_FLUSH(ctx); + _mesa_flush(ctx); +} + + +/** + * Set mvp_with_dp4 flag. If a driver has a preference for DP4 over + * MUL/MAD, or vice versa, call this function to register that. + * Otherwise we default to MUL/MAD. + */ +void +_mesa_set_mvp_with_dp4( struct gl_context *ctx, + GLboolean flag ) +{ + ctx->mvp_with_dp4 = flag; +} + + + +/** + * Prior to drawing anything with glBegin, glDrawArrays, etc. this function + * is called to see if it's valid to render. This involves checking that + * the current shader is valid and the framebuffer is complete. + * If an error is detected it'll be recorded here. + * \return GL_TRUE if OK to render, GL_FALSE if not + */ +GLboolean +_mesa_valid_to_render(struct gl_context *ctx, const char *where) +{ + bool vert_from_glsl_shader = false; + bool geom_from_glsl_shader = false; + bool frag_from_glsl_shader = false; + + /* This depends on having up to date derived state (shaders) */ + if (ctx->NewState) + _mesa_update_state(ctx); + + if (ctx->Shader.CurrentVertexProgram) { + vert_from_glsl_shader = true; + + if (!ctx->Shader.CurrentVertexProgram->LinkStatus) { + _mesa_error(ctx, GL_INVALID_OPERATION, + "%s(shader not linked)", where); + return GL_FALSE; + } +#if 0 /* not normally enabled */ + { + char errMsg[100]; + if (!_mesa_validate_shader_program(ctx, + ctx->Shader.CurrentVertexProgram, + errMsg)) { + _mesa_warning(ctx, "Shader program %u is invalid: %s", + ctx->Shader.CurrentVertexProgram->Name, errMsg); + } + } +#endif + } + + if (ctx->Shader.CurrentGeometryProgram) { + geom_from_glsl_shader = true; + + if (!ctx->Shader.CurrentGeometryProgram->LinkStatus) { + _mesa_error(ctx, GL_INVALID_OPERATION, + "%s(shader not linked)", where); + return GL_FALSE; + } +#if 0 /* not normally enabled */ + { + char errMsg[100]; + if (!_mesa_validate_shader_program(ctx, + ctx->Shader.CurrentGeometryProgram, + errMsg)) { + _mesa_warning(ctx, "Shader program %u is invalid: %s", + ctx->Shader.CurrentGeometryProgram->Name, errMsg); + } + } +#endif + } + + if (ctx->Shader.CurrentFragmentProgram) { + frag_from_glsl_shader = true; + + if (!ctx->Shader.CurrentFragmentProgram->LinkStatus) { + _mesa_error(ctx, GL_INVALID_OPERATION, + "%s(shader not linked)", where); + return GL_FALSE; + } +#if 0 /* not normally enabled */ + { + char errMsg[100]; + if (!_mesa_validate_shader_program(ctx, + ctx->Shader.CurrentFragmentProgram, + errMsg)) { + _mesa_warning(ctx, "Shader program %u is invalid: %s", + ctx->Shader.CurrentFragmentProgram->Name, errMsg); + } + } +#endif + } + + /* Any shader stages that are not supplied by the GLSL shader and have + * assembly shaders enabled must now be validated. + */ + if (!vert_from_glsl_shader + && ctx->VertexProgram.Enabled && !ctx->VertexProgram._Enabled) { + _mesa_error(ctx, GL_INVALID_OPERATION, + "%s(vertex program not valid)", where); + return GL_FALSE; + } + + /* FINISHME: If GL_NV_geometry_program4 is ever supported, the current + * FINISHME: geometry program should validated here. + */ + (void) geom_from_glsl_shader; + + if (!frag_from_glsl_shader) { + if (ctx->FragmentProgram.Enabled && !ctx->FragmentProgram._Enabled) { + _mesa_error(ctx, GL_INVALID_OPERATION, + "%s(fragment program not valid)", where); + return GL_FALSE; + } + + /* If drawing to integer-valued color buffers, there must be an + * active fragment shader (GL_EXT_texture_integer). + */ + if (ctx->DrawBuffer && ctx->DrawBuffer->_IntegerColor) { + _mesa_error(ctx, GL_INVALID_OPERATION, + "%s(integer format but no fragment shader)", where); + return GL_FALSE; + } + } + + if (ctx->DrawBuffer->_Status != GL_FRAMEBUFFER_COMPLETE_EXT) { + _mesa_error(ctx, GL_INVALID_FRAMEBUFFER_OPERATION_EXT, + "%s(incomplete framebuffer)", where); + return GL_FALSE; + } + +#ifdef DEBUG + if (ctx->Shader.Flags & GLSL_LOG) { + struct gl_shader_program *shProg[MESA_SHADER_TYPES]; + gl_shader_type i; + + shProg[MESA_SHADER_VERTEX] = ctx->Shader.CurrentVertexProgram; + shProg[MESA_SHADER_GEOMETRY] = ctx->Shader.CurrentGeometryProgram; + shProg[MESA_SHADER_FRAGMENT] = ctx->Shader.CurrentFragmentProgram; + + for (i = 0; i < MESA_SHADER_TYPES; i++) { + struct gl_shader *sh; + + if (shProg[i] == NULL || shProg[i]->_Used + || shProg[i]->_LinkedShaders[i] == NULL) + continue; + + /* This is the first time this shader is being used. + * Append shader's constants/uniforms to log file. + * + * The logic is a little odd here. We only want to log data for each + * shader target that will actually be used, and we only want to log + * it once. It's possible to have a program bound to the vertex + * shader target that also supplied a fragment shader. If that + * program isn't also bound to the fragment shader target we don't + * want to log its fragment data. + */ + sh = shProg[i]->_LinkedShaders[i]; + switch (sh->Type) { + case GL_VERTEX_SHADER: + _mesa_append_uniforms_to_file(sh, &shProg[i]->VertexProgram->Base); + break; + + case GL_GEOMETRY_SHADER_ARB: + _mesa_append_uniforms_to_file(sh, + &shProg[i]->GeometryProgram->Base); + break; + + case GL_FRAGMENT_SHADER: + _mesa_append_uniforms_to_file(sh, + &shProg[i]->FragmentProgram->Base); + break; + } + } + + for (i = 0; i < MESA_SHADER_TYPES; i++) { + if (shProg[i] != NULL) + shProg[i]->_Used = GL_TRUE; + } + } +#endif + + return GL_TRUE; +} + + +/*@}*/ diff --git a/mesalib/src/mesa/main/context.h b/mesalib/src/mesa/main/context.h index ae4d6f7da..a4c7ba2c5 100644 --- a/mesalib/src/mesa/main/context.h +++ b/mesalib/src/mesa/main/context.h @@ -1,289 +1,289 @@ -/*
- * Mesa 3-D graphics library
- * Version: 6.5.1
- *
- * Copyright (C) 1999-2006 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
- * BRIAN PAUL 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 context.h
- * Mesa context and visual-related functions.
- *
- * There are three large Mesa data types/classes which are meant to be
- * used by device drivers:
- * - struct gl_context: this contains the Mesa rendering state
- * - struct gl_config: this describes the color buffer (RGB vs. ci), whether or not
- * there's a depth buffer, stencil buffer, etc.
- * - struct gl_framebuffer: contains pointers to the depth buffer, stencil buffer,
- * accum buffer and alpha buffers.
- *
- * These types should be encapsulated by corresponding device driver
- * data types. See xmesa.h and xmesaP.h for an example.
- *
- * In OOP terms, struct gl_context, struct gl_config, and struct gl_framebuffer are base classes
- * which the device driver must derive from.
- *
- * The following functions create and destroy these data types.
- */
-
-
-#ifndef CONTEXT_H
-#define CONTEXT_H
-
-
-#include "imports.h"
-#include "mtypes.h"
-
-
-struct _glapi_table;
-
-
-/** \name Visual-related functions */
-/*@{*/
-
-extern struct gl_config *
-_mesa_create_visual( GLboolean dbFlag,
- GLboolean stereoFlag,
- GLint redBits,
- GLint greenBits,
- GLint blueBits,
- GLint alphaBits,
- GLint depthBits,
- GLint stencilBits,
- GLint accumRedBits,
- GLint accumGreenBits,
- GLint accumBlueBits,
- GLint accumAlphaBits,
- GLint numSamples );
-
-extern GLboolean
-_mesa_initialize_visual( struct gl_config *v,
- GLboolean dbFlag,
- GLboolean stereoFlag,
- GLint redBits,
- GLint greenBits,
- GLint blueBits,
- GLint alphaBits,
- GLint depthBits,
- GLint stencilBits,
- GLint accumRedBits,
- GLint accumGreenBits,
- GLint accumBlueBits,
- GLint accumAlphaBits,
- GLint numSamples );
-
-extern void
-_mesa_destroy_visual( struct gl_config *vis );
-
-/*@}*/
-
-
-/** \name Context-related functions */
-/*@{*/
-
-extern GLboolean
-_mesa_initialize_context( struct gl_context *ctx,
- gl_api api,
- const struct gl_config *visual,
- struct gl_context *share_list,
- const struct dd_function_table *driverFunctions,
- void *driverContext );
-
-extern struct gl_context *
-_mesa_create_context(gl_api api,
- const struct gl_config *visual,
- struct gl_context *share_list,
- const struct dd_function_table *driverFunctions,
- void *driverContext);
-
-extern void
-_mesa_free_context_data( struct gl_context *ctx );
-
-extern void
-_mesa_destroy_context( struct gl_context *ctx );
-
-
-extern void
-_mesa_copy_context(const struct gl_context *src, struct gl_context *dst, GLuint mask);
-
-
-extern void
-_mesa_check_init_viewport(struct gl_context *ctx, GLuint width, GLuint height);
-
-extern GLboolean
-_mesa_make_current( struct gl_context *ctx, struct gl_framebuffer *drawBuffer,
- struct gl_framebuffer *readBuffer );
-
-extern GLboolean
-_mesa_share_state(struct gl_context *ctx, struct gl_context *ctxToShare);
-
-extern struct gl_context *
-_mesa_get_current_context(void);
-
-/*@}*/
-
-extern void
-_mesa_init_get_hash(struct gl_context *ctx);
-
-extern void
-_mesa_notifySwapBuffers(struct gl_context *gc);
-
-
-extern struct _glapi_table *
-_mesa_get_dispatch(struct gl_context *ctx);
-
-
-void
-_mesa_set_mvp_with_dp4( struct gl_context *ctx,
- GLboolean flag );
-
-
-extern GLboolean
-_mesa_valid_to_render(struct gl_context *ctx, const char *where);
-
-
-
-/** \name Miscellaneous */
-/*@{*/
-
-extern void
-_mesa_record_error( struct gl_context *ctx, GLenum error );
-
-
-extern void
-_mesa_finish(struct gl_context *ctx);
-
-extern void
-_mesa_flush(struct gl_context *ctx);
-
-
-extern void GLAPIENTRY
-_mesa_Finish( void );
-
-extern void GLAPIENTRY
-_mesa_Flush( void );
-
-/*@}*/
-
-
-/**
- * \name Macros for flushing buffered rendering commands before state changes,
- * checking if inside glBegin/glEnd, etc.
- */
-/*@{*/
-
-/**
- * Flush vertices.
- *
- * \param ctx GL context.
- * \param newstate new state.
- *
- * Checks if dd_function_table::NeedFlush is marked to flush stored vertices,
- * and calls dd_function_table::FlushVertices if so. Marks
- * __struct gl_contextRec::NewState with \p newstate.
- */
-#define FLUSH_VERTICES(ctx, newstate) \
-do { \
- if (MESA_VERBOSE & VERBOSE_STATE) \
- _mesa_debug(ctx, "FLUSH_VERTICES in %s\n", MESA_FUNCTION);\
- if (ctx->Driver.NeedFlush & FLUSH_STORED_VERTICES) \
- ctx->Driver.FlushVertices(ctx, FLUSH_STORED_VERTICES); \
- ctx->NewState |= newstate; \
-} while (0)
-
-/**
- * Flush current state.
- *
- * \param ctx GL context.
- * \param newstate new state.
- *
- * Checks if dd_function_table::NeedFlush is marked to flush current state,
- * and calls dd_function_table::FlushVertices if so. Marks
- * __struct gl_contextRec::NewState with \p newstate.
- */
-#define FLUSH_CURRENT(ctx, newstate) \
-do { \
- if (MESA_VERBOSE & VERBOSE_STATE) \
- _mesa_debug(ctx, "FLUSH_CURRENT in %s\n", MESA_FUNCTION); \
- if (ctx->Driver.NeedFlush & FLUSH_UPDATE_CURRENT) \
- ctx->Driver.FlushVertices(ctx, FLUSH_UPDATE_CURRENT); \
- ctx->NewState |= newstate; \
-} while (0)
-
-/**
- * Macro to assert that the API call was made outside the
- * glBegin()/glEnd() pair, with return value.
- *
- * \param ctx GL context.
- * \param retval value to return value in case the assertion fails.
- */
-#define ASSERT_OUTSIDE_BEGIN_END_WITH_RETVAL(ctx, retval) \
-do { \
- if (ctx->Driver.CurrentExecPrimitive != PRIM_OUTSIDE_BEGIN_END) { \
- _mesa_error(ctx, GL_INVALID_OPERATION, "Inside glBegin/glEnd"); \
- return retval; \
- } \
-} while (0)
-
-/**
- * Macro to assert that the API call was made outside the
- * glBegin()/glEnd() pair.
- *
- * \param ctx GL context.
- */
-#define ASSERT_OUTSIDE_BEGIN_END(ctx) \
-do { \
- if (ctx->Driver.CurrentExecPrimitive != PRIM_OUTSIDE_BEGIN_END) { \
- _mesa_error(ctx, GL_INVALID_OPERATION, "Inside glBegin/glEnd"); \
- return; \
- } \
-} while (0)
-
-/**
- * Macro to assert that the API call was made outside the
- * glBegin()/glEnd() pair and flush the vertices.
- *
- * \param ctx GL context.
- */
-#define ASSERT_OUTSIDE_BEGIN_END_AND_FLUSH(ctx) \
-do { \
- ASSERT_OUTSIDE_BEGIN_END(ctx); \
- FLUSH_VERTICES(ctx, 0); \
-} while (0)
-
-/**
- * Macro to assert that the API call was made outside the
- * glBegin()/glEnd() pair and flush the vertices, with return value.
- *
- * \param ctx GL context.
- * \param retval value to return value in case the assertion fails.
- */
-#define ASSERT_OUTSIDE_BEGIN_END_AND_FLUSH_WITH_RETVAL(ctx, retval) \
-do { \
- ASSERT_OUTSIDE_BEGIN_END_WITH_RETVAL(ctx, retval); \
- FLUSH_VERTICES(ctx, 0); \
-} while (0)
-
-/*@}*/
-
-
-
-#endif /* CONTEXT_H */
+/* + * Mesa 3-D graphics library + * Version: 6.5.1 + * + * Copyright (C) 1999-2006 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 + * BRIAN PAUL 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 context.h + * Mesa context and visual-related functions. + * + * There are three large Mesa data types/classes which are meant to be + * used by device drivers: + * - struct gl_context: this contains the Mesa rendering state + * - struct gl_config: this describes the color buffer (RGB vs. ci), whether + * or not there's a depth buffer, stencil buffer, etc. + * - struct gl_framebuffer: contains pointers to the depth buffer, stencil + * buffer, accum buffer and alpha buffers. + * + * These types should be encapsulated by corresponding device driver + * data types. See xmesa.h and xmesaP.h for an example. + * + * In OOP terms, struct gl_context, struct gl_config, and struct gl_framebuffer + * are base classes which the device driver must derive from. + * + * The following functions create and destroy these data types. + */ + + +#ifndef CONTEXT_H +#define CONTEXT_H + + +#include "imports.h" +#include "mtypes.h" + + +struct _glapi_table; + + +/** \name Visual-related functions */ +/*@{*/ + +extern struct gl_config * +_mesa_create_visual( GLboolean dbFlag, + GLboolean stereoFlag, + GLint redBits, + GLint greenBits, + GLint blueBits, + GLint alphaBits, + GLint depthBits, + GLint stencilBits, + GLint accumRedBits, + GLint accumGreenBits, + GLint accumBlueBits, + GLint accumAlphaBits, + GLint numSamples ); + +extern GLboolean +_mesa_initialize_visual( struct gl_config *v, + GLboolean dbFlag, + GLboolean stereoFlag, + GLint redBits, + GLint greenBits, + GLint blueBits, + GLint alphaBits, + GLint depthBits, + GLint stencilBits, + GLint accumRedBits, + GLint accumGreenBits, + GLint accumBlueBits, + GLint accumAlphaBits, + GLint numSamples ); + +extern void +_mesa_destroy_visual( struct gl_config *vis ); + +/*@}*/ + + +/** \name Context-related functions */ +/*@{*/ + +extern GLboolean +_mesa_initialize_context( struct gl_context *ctx, + gl_api api, + const struct gl_config *visual, + struct gl_context *share_list, + const struct dd_function_table *driverFunctions, + void *driverContext ); + +extern struct gl_context * +_mesa_create_context(gl_api api, + const struct gl_config *visual, + struct gl_context *share_list, + const struct dd_function_table *driverFunctions, + void *driverContext); + +extern void +_mesa_free_context_data( struct gl_context *ctx ); + +extern void +_mesa_destroy_context( struct gl_context *ctx ); + + +extern void +_mesa_copy_context(const struct gl_context *src, struct gl_context *dst, GLuint mask); + + +extern void +_mesa_check_init_viewport(struct gl_context *ctx, GLuint width, GLuint height); + +extern GLboolean +_mesa_make_current( struct gl_context *ctx, struct gl_framebuffer *drawBuffer, + struct gl_framebuffer *readBuffer ); + +extern GLboolean +_mesa_share_state(struct gl_context *ctx, struct gl_context *ctxToShare); + +extern struct gl_context * +_mesa_get_current_context(void); + +/*@}*/ + +extern void +_mesa_init_get_hash(struct gl_context *ctx); + +extern void +_mesa_notifySwapBuffers(struct gl_context *gc); + + +extern struct _glapi_table * +_mesa_get_dispatch(struct gl_context *ctx); + + +void +_mesa_set_mvp_with_dp4( struct gl_context *ctx, + GLboolean flag ); + + +extern GLboolean +_mesa_valid_to_render(struct gl_context *ctx, const char *where); + + + +/** \name Miscellaneous */ +/*@{*/ + +extern void +_mesa_record_error( struct gl_context *ctx, GLenum error ); + + +extern void +_mesa_finish(struct gl_context *ctx); + +extern void +_mesa_flush(struct gl_context *ctx); + + +extern void GLAPIENTRY +_mesa_Finish( void ); + +extern void GLAPIENTRY +_mesa_Flush( void ); + +/*@}*/ + + +/** + * \name Macros for flushing buffered rendering commands before state changes, + * checking if inside glBegin/glEnd, etc. + */ +/*@{*/ + +/** + * Flush vertices. + * + * \param ctx GL context. + * \param newstate new state. + * + * Checks if dd_function_table::NeedFlush is marked to flush stored vertices, + * and calls dd_function_table::FlushVertices if so. Marks + * __struct gl_contextRec::NewState with \p newstate. + */ +#define FLUSH_VERTICES(ctx, newstate) \ +do { \ + if (MESA_VERBOSE & VERBOSE_STATE) \ + _mesa_debug(ctx, "FLUSH_VERTICES in %s\n", MESA_FUNCTION);\ + if (ctx->Driver.NeedFlush & FLUSH_STORED_VERTICES) \ + ctx->Driver.FlushVertices(ctx, FLUSH_STORED_VERTICES); \ + ctx->NewState |= newstate; \ +} while (0) + +/** + * Flush current state. + * + * \param ctx GL context. + * \param newstate new state. + * + * Checks if dd_function_table::NeedFlush is marked to flush current state, + * and calls dd_function_table::FlushVertices if so. Marks + * __struct gl_contextRec::NewState with \p newstate. + */ +#define FLUSH_CURRENT(ctx, newstate) \ +do { \ + if (MESA_VERBOSE & VERBOSE_STATE) \ + _mesa_debug(ctx, "FLUSH_CURRENT in %s\n", MESA_FUNCTION); \ + if (ctx->Driver.NeedFlush & FLUSH_UPDATE_CURRENT) \ + ctx->Driver.FlushVertices(ctx, FLUSH_UPDATE_CURRENT); \ + ctx->NewState |= newstate; \ +} while (0) + +/** + * Macro to assert that the API call was made outside the + * glBegin()/glEnd() pair, with return value. + * + * \param ctx GL context. + * \param retval value to return value in case the assertion fails. + */ +#define ASSERT_OUTSIDE_BEGIN_END_WITH_RETVAL(ctx, retval) \ +do { \ + if (ctx->Driver.CurrentExecPrimitive != PRIM_OUTSIDE_BEGIN_END) { \ + _mesa_error(ctx, GL_INVALID_OPERATION, "Inside glBegin/glEnd"); \ + return retval; \ + } \ +} while (0) + +/** + * Macro to assert that the API call was made outside the + * glBegin()/glEnd() pair. + * + * \param ctx GL context. + */ +#define ASSERT_OUTSIDE_BEGIN_END(ctx) \ +do { \ + if (ctx->Driver.CurrentExecPrimitive != PRIM_OUTSIDE_BEGIN_END) { \ + _mesa_error(ctx, GL_INVALID_OPERATION, "Inside glBegin/glEnd"); \ + return; \ + } \ +} while (0) + +/** + * Macro to assert that the API call was made outside the + * glBegin()/glEnd() pair and flush the vertices. + * + * \param ctx GL context. + */ +#define ASSERT_OUTSIDE_BEGIN_END_AND_FLUSH(ctx) \ +do { \ + ASSERT_OUTSIDE_BEGIN_END(ctx); \ + FLUSH_VERTICES(ctx, 0); \ +} while (0) + +/** + * Macro to assert that the API call was made outside the + * glBegin()/glEnd() pair and flush the vertices, with return value. + * + * \param ctx GL context. + * \param retval value to return value in case the assertion fails. + */ +#define ASSERT_OUTSIDE_BEGIN_END_AND_FLUSH_WITH_RETVAL(ctx, retval) \ +do { \ + ASSERT_OUTSIDE_BEGIN_END_WITH_RETVAL(ctx, retval); \ + FLUSH_VERTICES(ctx, 0); \ +} while (0) + +/*@}*/ + + + +#endif /* CONTEXT_H */ diff --git a/mesalib/src/mesa/main/extensions.c b/mesalib/src/mesa/main/extensions.c index e5711f21a..c45265900 100644 --- a/mesalib/src/mesa/main/extensions.c +++ b/mesalib/src/mesa/main/extensions.c @@ -262,6 +262,7 @@ static const struct extension extension_table[] = { { "GL_APPLE_packed_pixels", o(APPLE_packed_pixels), GL, 2002 }, { "GL_APPLE_vertex_array_object", o(APPLE_vertex_array_object), GL, 2002 }, { "GL_ATI_blend_equation_separate", o(EXT_blend_equation_separate), GL, 2003 }, + { "GL_ATI_draw_buffers", o(ARB_draw_buffers), GL, 2002 }, { "GL_ATI_envmap_bumpmap", o(ATI_envmap_bumpmap), GL, 2001 }, { "GL_ATI_fragment_shader", o(ATI_fragment_shader), GL, 2001 }, { "GL_ATI_separate_stencil", o(ATI_separate_stencil), GL, 2006 }, diff --git a/mesalib/src/mesa/main/samplerobj.c b/mesalib/src/mesa/main/samplerobj.c index 55acb6d1f..2d3879c06 100644 --- a/mesalib/src/mesa/main/samplerobj.c +++ b/mesalib/src/mesa/main/samplerobj.c @@ -63,7 +63,7 @@ _mesa_reference_sampler_object(struct gl_context *ctx, return; if (*ptr) { - /* Unreference the old buffer */ + /* Unreference the old sampler */ GLboolean deleteFlag = GL_FALSE; struct gl_sampler_object *oldSamp = *ptr; @@ -90,9 +90,9 @@ _mesa_reference_sampler_object(struct gl_context *ctx, /* reference new sampler */ /*_glthread_LOCK_MUTEX(samp->Mutex);*/ if (samp->RefCount == 0) { - /* this buffer's being deleted (look just above) */ + /* this sampler's being deleted (look just above) */ /* Not sure this can every really happen. Warn if it does. */ - _mesa_problem(NULL, "referencing deleted buffer object"); + _mesa_problem(NULL, "referencing deleted sampler object"); *ptr = NULL; } else { @@ -281,7 +281,7 @@ _mesa_BindSampler(GLuint unit, GLuint sampler) /** - * Check if a coordinate wrap mode is supported for the texture target. + * Check if a coordinate wrap mode is legal. * \return GL_TRUE if legal, GL_FALSE otherwise */ static GLboolean diff --git a/mesalib/src/mesa/main/shared.c b/mesalib/src/mesa/main/shared.c index e470d873f..d84f59690 100644 --- a/mesalib/src/mesa/main/shared.c +++ b/mesalib/src/mesa/main/shared.c @@ -27,8 +27,6 @@ * Shared-context state */ - - #include "imports.h" #include "mfeatures.h" #include "mtypes.h" @@ -46,6 +44,7 @@ #include "shaderobj.h" #include "syncobj.h" + /** * Allocate and initialize a shared context state structure. * Initializes the display list, texture objects and vertex programs hash @@ -403,7 +402,8 @@ free_shared_state(struct gl_context *ctx, struct gl_shared_state *shared) * \sa free_shared_state(). */ void -_mesa_release_shared_state(struct gl_context *ctx, struct gl_shared_state *shared) +_mesa_release_shared_state(struct gl_context *ctx, + struct gl_shared_state *shared) { GLint RefCount; diff --git a/mesalib/src/mesa/main/shared.h b/mesalib/src/mesa/main/shared.h index 870aadeb2..55516a8c3 100644 --- a/mesalib/src/mesa/main/shared.h +++ b/mesalib/src/mesa/main/shared.h @@ -1,38 +1,39 @@ -/*
- * Mesa 3-D graphics library
- * Version: 7.5
- *
- * 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
- * BRIAN PAUL 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 SHARED_H
-#define SHARED_H
-
-struct gl_context;
-
-struct gl_shared_state *
-_mesa_alloc_shared_state(struct gl_context *ctx);
-
-
-void
-_mesa_release_shared_state(struct gl_context *ctx, struct gl_shared_state *shared);
-
-
-#endif
+/* + * Mesa 3-D graphics library + * Version: 7.5 + * + * 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 + * BRIAN PAUL 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 SHARED_H +#define SHARED_H + +struct gl_context; + +struct gl_shared_state * +_mesa_alloc_shared_state(struct gl_context *ctx); + + +void +_mesa_release_shared_state(struct gl_context *ctx, + struct gl_shared_state *shared); + + +#endif diff --git a/mesalib/src/mesa/program/program_parse.y b/mesalib/src/mesa/program/program_parse.y index 19aa8ccdb..b35bc5a7c 100644 --- a/mesalib/src/mesa/program/program_parse.y +++ b/mesalib/src/mesa/program/program_parse.y @@ -2064,6 +2064,34 @@ optResultFaceType: ? VERT_RESULT_COL0 : FRAG_RESULT_COLOR; } + | '[' INTEGER ']' + { + if (state->mode == ARB_vertex) { + yyerror(& @1, state, "invalid program result name"); + YYERROR; + } else { + if (!state->option.DrawBuffers) { + /* From the ARB_draw_buffers spec (same text exists + * for ATI_draw_buffers): + * + * If this option is not specified, a fragment + * program that attempts to bind + * "result.color[n]" will fail to load, and only + * "result.color" will be allowed. + */ + yyerror(& @1, state, + "result.color[] used without " + "`OPTION ARB_draw_buffers' or " + "`OPTION ATI_draw_buffers'"); + YYERROR; + } else if ($2 >= state->MaxDrawBuffers) { + yyerror(& @1, state, + "result.color[] exceeds MAX_DRAW_BUFFERS_ARB"); + YYERROR; + } + $$ = FRAG_RESULT_DATA0 + $2; + } + } | FRONT { if (state->mode == ARB_vertex) { @@ -2681,6 +2709,7 @@ _mesa_parse_arb_program(struct gl_context *ctx, GLenum target, const GLubyte *st state->MaxClipPlanes = ctx->Const.MaxClipPlanes; state->MaxLights = ctx->Const.MaxLights; state->MaxProgramMatrices = ctx->Const.MaxProgramMatrices; + state->MaxDrawBuffers = ctx->Const.MaxDrawBuffers; state->state_param_enum = (target == GL_VERTEX_PROGRAM_ARB) ? STATE_VERTEX_PROGRAM : STATE_FRAGMENT_PROGRAM; diff --git a/mesalib/src/mesa/program/program_parse_extra.c b/mesalib/src/mesa/program/program_parse_extra.c index ae98b782b..4d928483e 100644 --- a/mesalib/src/mesa/program/program_parse_extra.c +++ b/mesalib/src/mesa/program/program_parse_extra.c @@ -229,6 +229,16 @@ _mesa_ARBfp_parse_option(struct asm_parser_state *state, const char *option) } } } + } else if (strncmp(option, "ATI_", 4) == 0) { + option += 4; + + if (strcmp(option, "draw_buffers") == 0) { + /* Don't need to check extension availability because all Mesa-based + * drivers support GL_ATI_draw_buffers. + */ + state->option.DrawBuffers = 1; + return 1; + } } else if (strncmp(option, "NV_fragment_program", 19) == 0) { option += 19; diff --git a/mesalib/src/mesa/program/program_parser.h b/mesalib/src/mesa/program/program_parser.h index ff2f4f25f..8e5aaee95 100644 --- a/mesalib/src/mesa/program/program_parser.h +++ b/mesalib/src/mesa/program/program_parser.h @@ -1,299 +1,300 @@ -/*
- * Copyright © 2009 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.
- */
-#pragma once
-
-#include "main/config.h"
-
-struct gl_context;
-
-enum asm_type {
- at_none,
- at_address,
- at_attrib,
- at_param,
- at_temp,
- at_output
-};
-
-struct asm_symbol {
- struct asm_symbol *next; /**< List linkage for freeing. */
- const char *name;
- enum asm_type type;
- unsigned attrib_binding;
- unsigned output_binding; /**< Output / result register number. */
-
- /**
- * One of PROGRAM_STATE_VAR, PROGRAM_LOCAL_PARAM, or PROGRAM_ENV_PARAM.
- */
- unsigned param_binding_type;
-
- /**
- * Offset into the program_parameter_list where the tokens representing our
- * bound state (or constants) start.
- */
- unsigned param_binding_begin;
-
- /**
- * Constants put into the parameter list may be swizzled. This
- * field contain's the symbol's swizzle. (SWIZZLE_X/Y/Z/W)
- */
- unsigned param_binding_swizzle;
-
- /* This is how many entries in the program_parameter_list we take up
- * with our state tokens or constants. Note that this is _not_ the same as
- * the number of param registers we eventually use.
- */
- unsigned param_binding_length;
-
- /**
- * Index of the temp register assigned to this variable.
- */
- unsigned temp_binding;
-
- /**
- * Flag whether or not a PARAM is an array
- */
- unsigned param_is_array:1;
-
-
- /**
- * Flag whether or not a PARAM array is accessed indirectly
- */
- unsigned param_accessed_indirectly:1;
-
-
- /**
- * \brief Is first pass of parameter layout done with this variable?
- *
- * The parameter layout routine operates in two passes. This flag tracks
- * whether or not the first pass has handled this variable.
- *
- * \sa _mesa_layout_parameters
- */
- unsigned pass1_done:1;
-};
-
-
-struct asm_vector {
- unsigned count;
- float data[4];
-};
-
-
-struct asm_swizzle_mask {
- unsigned swizzle:12;
- unsigned mask:4;
-};
-
-
-struct asm_src_register {
- struct prog_src_register Base;
-
- /**
- * Symbol associated with indirect access to parameter arrays.
- *
- * If \c Base::RelAddr is 1, this will point to the symbol for the parameter
- * that is being dereferenced. Further, \c Base::Index will be the offset
- * from the address register being used.
- */
- struct asm_symbol *Symbol;
-};
-
-
-struct asm_instruction {
- struct prog_instruction Base;
- struct asm_instruction *next;
- struct asm_src_register SrcReg[3];
-};
-
-
-struct asm_parser_state {
- struct gl_context *ctx;
- struct gl_program *prog;
-
- /**
- * Per-program target limits
- */
- struct gl_program_constants *limits;
-
- struct _mesa_symbol_table *st;
-
- /**
- * Linked list of symbols
- *
- * This list is \b only used when cleaning up compiler state and freeing
- * memory.
- */
- struct asm_symbol *sym;
-
- /**
- * State for the lexer.
- */
- void *scanner;
-
- /**
- * Linked list of instructions generated during parsing.
- */
- /*@{*/
- struct asm_instruction *inst_head;
- struct asm_instruction *inst_tail;
- /*@}*/
-
-
- /**
- * Selected limits copied from gl_constants
- *
- * These are limits from the GL context, but various bits in the program
- * must be validated against these values.
- */
- /*@{*/
- unsigned MaxTextureCoordUnits;
- unsigned MaxTextureImageUnits;
- unsigned MaxTextureUnits;
- unsigned MaxClipPlanes;
- unsigned MaxLights;
- unsigned MaxProgramMatrices;
- /*@}*/
-
- /**
- * Value to use in state vector accessors for environment and local
- * parameters
- */
- unsigned state_param_enum;
-
-
- /**
- * Input attributes bound to specific names
- *
- * This is only needed so that errors can be properly produced when
- * multiple ATTRIB statements bind illegal combinations of vertex
- * attributes.
- */
- unsigned InputsBound;
-
- enum {
- invalid_mode = 0,
- ARB_vertex,
- ARB_fragment
- } mode;
-
- struct {
- unsigned PositionInvariant:1;
- unsigned Fog:2;
- unsigned PrecisionHint:2;
- unsigned DrawBuffers:1;
- unsigned Shadow:1;
- unsigned TexRect:1;
- unsigned TexArray:1;
- unsigned NV_fragment:1;
- unsigned OriginUpperLeft:1;
- unsigned PixelCenterInteger:1;
- } option;
-
- struct {
- unsigned UsesKill:1;
- } fragment;
-};
-
-#define OPTION_NONE 0
-#define OPTION_FOG_EXP 1
-#define OPTION_FOG_EXP2 2
-#define OPTION_FOG_LINEAR 3
-#define OPTION_NICEST 1
-#define OPTION_FASTEST 2
-
-typedef struct YYLTYPE {
- int first_line;
- int first_column;
- int last_line;
- int last_column;
- int position;
-} YYLTYPE;
-
-#define YYLTYPE_IS_DECLARED 1
-#define YYLTYPE_IS_TRIVIAL 1
-
-
-extern GLboolean _mesa_parse_arb_program(struct gl_context *ctx, GLenum target,
- const GLubyte *str, GLsizei len, struct asm_parser_state *state);
-
-
-
-/* From program_lexer.l. */
-extern void _mesa_program_lexer_dtor(void *scanner);
-
-extern void _mesa_program_lexer_ctor(void **scanner,
- struct asm_parser_state *state, const char *string, size_t len);
-
-
-/**
- *\name From program_parse_extra.c
- */
-/*@{*/
-
-/**
- * Parses and processes an option string to an ARB vertex program
- *
- * \return
- * Non-zero on success, zero on failure.
- */
-extern int _mesa_ARBvp_parse_option(struct asm_parser_state *state,
- const char *option);
-
-/**
- * Parses and processes an option string to an ARB fragment program
- *
- * \return
- * Non-zero on success, zero on failure.
- */
-extern int _mesa_ARBfp_parse_option(struct asm_parser_state *state,
- const char *option);
-
-/**
- * Parses and processes instruction suffixes
- *
- * Instruction suffixes, such as \c _SAT, are processed. The relevant bits
- * are set in \c inst. If suffixes are encountered that are either not known
- * or not supported by the modes and options set in \c state, zero will be
- * returned.
- *
- * \return
- * Non-zero on success, zero on failure.
- */
-extern int _mesa_parse_instruction_suffix(const struct asm_parser_state *state,
- const char *suffix, struct prog_instruction *inst);
-
-/**
- * Parses a condition code name
- *
- * The condition code names (e.g., \c LT, \c GT, \c NE) were added to assembly
- * shaders with the \c GL_NV_fragment_program_option extension. This function
- * converts a string representation into one of the \c COND_ macros.
- *
- * \return
- * One of the \c COND_ macros defined in prog_instruction.h on success or zero
- * on failure.
- */
-extern int _mesa_parse_cc(const char *s);
-
-/*@}*/
+/* + * Copyright © 2009 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. + */ +#pragma once + +#include "main/config.h" + +struct gl_context; + +enum asm_type { + at_none, + at_address, + at_attrib, + at_param, + at_temp, + at_output +}; + +struct asm_symbol { + struct asm_symbol *next; /**< List linkage for freeing. */ + const char *name; + enum asm_type type; + unsigned attrib_binding; + unsigned output_binding; /**< Output / result register number. */ + + /** + * One of PROGRAM_STATE_VAR, PROGRAM_LOCAL_PARAM, or PROGRAM_ENV_PARAM. + */ + unsigned param_binding_type; + + /** + * Offset into the program_parameter_list where the tokens representing our + * bound state (or constants) start. + */ + unsigned param_binding_begin; + + /** + * Constants put into the parameter list may be swizzled. This + * field contain's the symbol's swizzle. (SWIZZLE_X/Y/Z/W) + */ + unsigned param_binding_swizzle; + + /* This is how many entries in the program_parameter_list we take up + * with our state tokens or constants. Note that this is _not_ the same as + * the number of param registers we eventually use. + */ + unsigned param_binding_length; + + /** + * Index of the temp register assigned to this variable. + */ + unsigned temp_binding; + + /** + * Flag whether or not a PARAM is an array + */ + unsigned param_is_array:1; + + + /** + * Flag whether or not a PARAM array is accessed indirectly + */ + unsigned param_accessed_indirectly:1; + + + /** + * \brief Is first pass of parameter layout done with this variable? + * + * The parameter layout routine operates in two passes. This flag tracks + * whether or not the first pass has handled this variable. + * + * \sa _mesa_layout_parameters + */ + unsigned pass1_done:1; +}; + + +struct asm_vector { + unsigned count; + float data[4]; +}; + + +struct asm_swizzle_mask { + unsigned swizzle:12; + unsigned mask:4; +}; + + +struct asm_src_register { + struct prog_src_register Base; + + /** + * Symbol associated with indirect access to parameter arrays. + * + * If \c Base::RelAddr is 1, this will point to the symbol for the parameter + * that is being dereferenced. Further, \c Base::Index will be the offset + * from the address register being used. + */ + struct asm_symbol *Symbol; +}; + + +struct asm_instruction { + struct prog_instruction Base; + struct asm_instruction *next; + struct asm_src_register SrcReg[3]; +}; + + +struct asm_parser_state { + struct gl_context *ctx; + struct gl_program *prog; + + /** + * Per-program target limits + */ + struct gl_program_constants *limits; + + struct _mesa_symbol_table *st; + + /** + * Linked list of symbols + * + * This list is \b only used when cleaning up compiler state and freeing + * memory. + */ + struct asm_symbol *sym; + + /** + * State for the lexer. + */ + void *scanner; + + /** + * Linked list of instructions generated during parsing. + */ + /*@{*/ + struct asm_instruction *inst_head; + struct asm_instruction *inst_tail; + /*@}*/ + + + /** + * Selected limits copied from gl_constants + * + * These are limits from the GL context, but various bits in the program + * must be validated against these values. + */ + /*@{*/ + unsigned MaxTextureCoordUnits; + unsigned MaxTextureImageUnits; + unsigned MaxTextureUnits; + unsigned MaxClipPlanes; + unsigned MaxLights; + unsigned MaxProgramMatrices; + unsigned MaxDrawBuffers; + /*@}*/ + + /** + * Value to use in state vector accessors for environment and local + * parameters + */ + unsigned state_param_enum; + + + /** + * Input attributes bound to specific names + * + * This is only needed so that errors can be properly produced when + * multiple ATTRIB statements bind illegal combinations of vertex + * attributes. + */ + unsigned InputsBound; + + enum { + invalid_mode = 0, + ARB_vertex, + ARB_fragment + } mode; + + struct { + unsigned PositionInvariant:1; + unsigned Fog:2; + unsigned PrecisionHint:2; + unsigned DrawBuffers:1; + unsigned Shadow:1; + unsigned TexRect:1; + unsigned TexArray:1; + unsigned NV_fragment:1; + unsigned OriginUpperLeft:1; + unsigned PixelCenterInteger:1; + } option; + + struct { + unsigned UsesKill:1; + } fragment; +}; + +#define OPTION_NONE 0 +#define OPTION_FOG_EXP 1 +#define OPTION_FOG_EXP2 2 +#define OPTION_FOG_LINEAR 3 +#define OPTION_NICEST 1 +#define OPTION_FASTEST 2 + +typedef struct YYLTYPE { + int first_line; + int first_column; + int last_line; + int last_column; + int position; +} YYLTYPE; + +#define YYLTYPE_IS_DECLARED 1 +#define YYLTYPE_IS_TRIVIAL 1 + + +extern GLboolean _mesa_parse_arb_program(struct gl_context *ctx, GLenum target, + const GLubyte *str, GLsizei len, struct asm_parser_state *state); + + + +/* From program_lexer.l. */ +extern void _mesa_program_lexer_dtor(void *scanner); + +extern void _mesa_program_lexer_ctor(void **scanner, + struct asm_parser_state *state, const char *string, size_t len); + + +/** + *\name From program_parse_extra.c + */ +/*@{*/ + +/** + * Parses and processes an option string to an ARB vertex program + * + * \return + * Non-zero on success, zero on failure. + */ +extern int _mesa_ARBvp_parse_option(struct asm_parser_state *state, + const char *option); + +/** + * Parses and processes an option string to an ARB fragment program + * + * \return + * Non-zero on success, zero on failure. + */ +extern int _mesa_ARBfp_parse_option(struct asm_parser_state *state, + const char *option); + +/** + * Parses and processes instruction suffixes + * + * Instruction suffixes, such as \c _SAT, are processed. The relevant bits + * are set in \c inst. If suffixes are encountered that are either not known + * or not supported by the modes and options set in \c state, zero will be + * returned. + * + * \return + * Non-zero on success, zero on failure. + */ +extern int _mesa_parse_instruction_suffix(const struct asm_parser_state *state, + const char *suffix, struct prog_instruction *inst); + +/** + * Parses a condition code name + * + * The condition code names (e.g., \c LT, \c GT, \c NE) were added to assembly + * shaders with the \c GL_NV_fragment_program_option extension. This function + * converts a string representation into one of the \c COND_ macros. + * + * \return + * One of the \c COND_ macros defined in prog_instruction.h on success or zero + * on failure. + */ +extern int _mesa_parse_cc(const char *s); + +/*@}*/ diff --git a/mesalib/src/mesa/state_tracker/st_atom_texture.c b/mesalib/src/mesa/state_tracker/st_atom_texture.c index e5fb8f868..19ad2e8cc 100644 --- a/mesalib/src/mesa/state_tracker/st_atom_texture.c +++ b/mesalib/src/mesa/state_tracker/st_atom_texture.c @@ -251,13 +251,15 @@ update_textures(struct st_context *st) st->state.num_textures = su + 1; /* if sampler view has changed dereference it */ - if (stObj->sampler_view) + if (stObj->sampler_view) { if (check_sampler_swizzle(stObj->sampler_view, stObj->base._Swizzle, samp->DepthMode) || (st_view_format != stObj->sampler_view->format) || - stObj->base.BaseLevel != stObj->sampler_view->u.tex.first_level) + stObj->base.BaseLevel != stObj->sampler_view->u.tex.first_level) { pipe_sampler_view_reference(&stObj->sampler_view, NULL); + } + } sampler_view = st_get_texture_sampler_view_from_stobj(stObj, pipe, samp, @@ -269,10 +271,12 @@ update_textures(struct st_context *st) cso_set_fragment_sampler_views(st->cso_context, st->state.num_textures, st->state.sampler_views); + if (st->ctx->Const.MaxVertexTextureImageUnits > 0) { + GLuint numUnits = MIN2(st->state.num_textures, + st->ctx->Const.MaxVertexTextureImageUnits); cso_set_vertex_sampler_views(st->cso_context, - MIN2(st->state.num_textures, - st->ctx->Const.MaxVertexTextureImageUnits), + numUnits, st->state.sampler_views); } } diff --git a/xorg-server/damageext/damageext.c b/xorg-server/damageext/damageext.c index 2b1514872..02db88a8e 100644 --- a/xorg-server/damageext/damageext.c +++ b/xorg-server/damageext/damageext.c @@ -1,521 +1,521 @@ -/*
- * Copyright © 2002 Keith Packard
- *
- * Permission to use, copy, modify, distribute, and sell this software and its
- * documentation for any purpose is hereby granted without fee, provided that
- * the above copyright notice appear in all copies and that both that
- * copyright notice and this permission notice appear in supporting
- * documentation, and that the name of Keith Packard not be used in
- * advertising or publicity pertaining to distribution of the software without
- * specific, written prior permission. Keith Packard makes no
- * representations about the suitability of this software for any purpose. It
- * is provided "as is" without express or implied warranty.
- *
- * KEITH PACKARD DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
- * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
- * EVENT SHALL KEITH PACKARD BE LIABLE FOR ANY SPECIAL, INDIRECT OR
- * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
- * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
- * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
- * PERFORMANCE OF THIS SOFTWARE.
- */
-
-#ifdef HAVE_DIX_CONFIG_H
-#include <dix-config.h>
-#endif
-
-#include "damageextint.h"
-#include "protocol-versions.h"
-
-static unsigned char DamageReqCode;
-static int DamageEventBase;
-static RESTYPE DamageExtType;
-static RESTYPE DamageExtWinType;
-
-static DevPrivateKeyRec DamageClientPrivateKeyRec;
-#define DamageClientPrivateKey (&DamageClientPrivateKeyRec)
-
-static void
-DamageExtNotify (DamageExtPtr pDamageExt, BoxPtr pBoxes, int nBoxes)
-{
- ClientPtr pClient = pDamageExt->pClient;
- DamageClientPtr pDamageClient = GetDamageClient (pClient);
- DrawablePtr pDrawable = pDamageExt->pDrawable;
- xDamageNotifyEvent ev;
- int i;
-
- UpdateCurrentTimeIf ();
- ev.type = DamageEventBase + XDamageNotify;
- ev.level = pDamageExt->level;
- ev.drawable = pDamageExt->drawable;
- ev.damage = pDamageExt->id;
- ev.timestamp = currentTime.milliseconds;
- ev.geometry.x = pDrawable->x;
- ev.geometry.y = pDrawable->y;
- ev.geometry.width = pDrawable->width;
- ev.geometry.height = pDrawable->height;
- if (pBoxes)
- {
- for (i = 0; i < nBoxes; i++)
- {
- ev.level = pDamageExt->level;
- if (i < nBoxes - 1)
- ev.level |= DamageNotifyMore;
- ev.area.x = pBoxes[i].x1;
- ev.area.y = pBoxes[i].y1;
- ev.area.width = pBoxes[i].x2 - pBoxes[i].x1;
- ev.area.height = pBoxes[i].y2 - pBoxes[i].y1;
- WriteEventsToClient (pClient, 1, (xEvent *) &ev);
- }
- }
- else
- {
- ev.area.x = 0;
- ev.area.y = 0;
- ev.area.width = pDrawable->width;
- ev.area.height = pDrawable->height;
- WriteEventsToClient (pClient, 1, (xEvent *) &ev);
- }
- /* Composite extension marks clients with manual Subwindows as critical */
- if (pDamageClient->critical > 0)
- {
- SetCriticalOutputPending ();
- pClient->smart_priority = SMART_MAX_PRIORITY;
- }
-}
-
-static void
-DamageExtReport (DamagePtr pDamage, RegionPtr pRegion, void *closure)
-{
- DamageExtPtr pDamageExt = closure;
-
- switch (pDamageExt->level) {
- case DamageReportRawRegion:
- case DamageReportDeltaRegion:
- DamageExtNotify (pDamageExt, RegionRects(pRegion), RegionNumRects(pRegion));
- break;
- case DamageReportBoundingBox:
- DamageExtNotify (pDamageExt, RegionExtents(pRegion), 1);
- break;
- case DamageReportNonEmpty:
- DamageExtNotify (pDamageExt, NullBox, 0);
- break;
- case DamageReportNone:
- break;
- }
-}
-
-static void
-DamageExtDestroy (DamagePtr pDamage, void *closure)
-{
- DamageExtPtr pDamageExt = closure;
-
- pDamageExt->pDamage = 0;
- if (pDamageExt->id)
- FreeResource (pDamageExt->id, RT_NONE);
-}
-
-void
-DamageExtSetCritical (ClientPtr pClient, Bool critical)
-{
- DamageClientPtr pDamageClient = GetDamageClient (pClient);
-
- if (pDamageClient)
- pDamageClient->critical += critical ? 1 : -1;
-}
-
-static int
-ProcDamageQueryVersion(ClientPtr client)
-{
- DamageClientPtr pDamageClient = GetDamageClient (client);
- xDamageQueryVersionReply rep;
- register int n;
- REQUEST(xDamageQueryVersionReq);
-
- REQUEST_SIZE_MATCH(xDamageQueryVersionReq);
- rep.type = X_Reply;
- rep.length = 0;
- rep.sequenceNumber = client->sequence;
- if (stuff->majorVersion < SERVER_DAMAGE_MAJOR_VERSION) {
- rep.majorVersion = stuff->majorVersion;
- rep.minorVersion = stuff->minorVersion;
- } else {
- rep.majorVersion = SERVER_DAMAGE_MAJOR_VERSION;
- if (stuff->majorVersion == SERVER_DAMAGE_MAJOR_VERSION &&
- stuff->minorVersion < SERVER_DAMAGE_MINOR_VERSION)
- rep.minorVersion = stuff->minorVersion;
- else
- rep.minorVersion = SERVER_DAMAGE_MINOR_VERSION;
- }
- pDamageClient->major_version = rep.majorVersion;
- pDamageClient->minor_version = rep.minorVersion;
- if (client->swapped) {
- swaps(&rep.sequenceNumber, n);
- swapl(&rep.length, n);
- swapl(&rep.majorVersion, n);
- swapl(&rep.minorVersion, n);
- }
- WriteToClient(client, sizeof(xDamageQueryVersionReply), (char *)&rep);
- return Success;
-}
-
-static int
-ProcDamageCreate (ClientPtr client)
-{
- DrawablePtr pDrawable;
- DamageExtPtr pDamageExt;
- DamageReportLevel level;
- RegionPtr pRegion;
- int rc;
-
- REQUEST(xDamageCreateReq);
-
- REQUEST_SIZE_MATCH(xDamageCreateReq);
- LEGAL_NEW_RESOURCE(stuff->damage, client);
- rc = dixLookupDrawable(&pDrawable, stuff->drawable, client, 0,
- DixGetAttrAccess|DixReadAccess);
- if (rc != Success)
- return rc;
-
- switch (stuff->level) {
- case XDamageReportRawRectangles:
- level = DamageReportRawRegion;
- break;
- case XDamageReportDeltaRectangles:
- level = DamageReportDeltaRegion;
- break;
- case XDamageReportBoundingBox:
- level = DamageReportBoundingBox;
- break;
- case XDamageReportNonEmpty:
- level = DamageReportNonEmpty;
- break;
- default:
- client->errorValue = stuff->level;
- return BadValue;
- }
-
- pDamageExt = malloc(sizeof (DamageExtRec));
- if (!pDamageExt)
- return BadAlloc;
- pDamageExt->id = stuff->damage;
- pDamageExt->drawable = stuff->drawable;
- pDamageExt->pDrawable = pDrawable;
- pDamageExt->level = level;
- pDamageExt->pClient = client;
- pDamageExt->pDamage = DamageCreate (DamageExtReport,
- DamageExtDestroy,
- level,
- FALSE,
- pDrawable->pScreen,
- pDamageExt);
- if (!pDamageExt->pDamage)
- {
- free(pDamageExt);
- return BadAlloc;
- }
- if (!AddResource (stuff->damage, DamageExtType, (pointer) pDamageExt))
- return BadAlloc;
-
- DamageSetReportAfterOp (pDamageExt->pDamage, TRUE);
- DamageRegister (pDamageExt->pDrawable, pDamageExt->pDamage);
-
- if (pDrawable->type == DRAWABLE_WINDOW)
- {
- pRegion = &((WindowPtr) pDrawable)->borderClip;
- DamageDamageRegion(pDrawable, pRegion);
- }
-
- return Success;
-}
-
-static int
-ProcDamageDestroy (ClientPtr client)
-{
- REQUEST(xDamageDestroyReq);
- DamageExtPtr pDamageExt;
-
- REQUEST_SIZE_MATCH(xDamageDestroyReq);
- VERIFY_DAMAGEEXT(pDamageExt, stuff->damage, client, DixWriteAccess);
- FreeResource (stuff->damage, RT_NONE);
- return Success;
-}
-
-static int
-ProcDamageSubtract (ClientPtr client)
-{
- REQUEST(xDamageSubtractReq);
- DamageExtPtr pDamageExt;
- RegionPtr pRepair;
- RegionPtr pParts;
-
- REQUEST_SIZE_MATCH(xDamageSubtractReq);
- VERIFY_DAMAGEEXT(pDamageExt, stuff->damage, client, DixWriteAccess);
- VERIFY_REGION_OR_NONE(pRepair, stuff->repair, client, DixWriteAccess);
- VERIFY_REGION_OR_NONE(pParts, stuff->parts, client, DixWriteAccess);
-
- if (pDamageExt->level != DamageReportRawRegion)
- {
- DamagePtr pDamage = pDamageExt->pDamage;
- if (pRepair)
- {
- if (pParts)
- RegionIntersect(pParts, DamageRegion (pDamage), pRepair);
- if (DamageSubtract (pDamage, pRepair))
- DamageExtReport (pDamage, DamageRegion (pDamage), (void *) pDamageExt);
- }
- else
- {
- if (pParts)
- RegionCopy(pParts, DamageRegion (pDamage));
- DamageEmpty (pDamage);
- }
- }
- return Success;
-}
-
-static int
-ProcDamageAdd (ClientPtr client)
-{
- REQUEST(xDamageAddReq);
- DrawablePtr pDrawable;
- RegionPtr pRegion;
- int rc;
-
- REQUEST_SIZE_MATCH(xDamageAddReq);
- VERIFY_REGION(pRegion, stuff->region, client, DixWriteAccess);
- rc = dixLookupDrawable(&pDrawable, stuff->drawable, client, 0,
- DixWriteAccess);
- if (rc != Success)
- return rc;
-
- /* The region is relative to the drawable origin, so translate it out to
- * screen coordinates like damage expects.
- */
- RegionTranslate(pRegion, pDrawable->x, pDrawable->y);
- DamageDamageRegion(pDrawable, pRegion);
- RegionTranslate(pRegion, -pDrawable->x, -pDrawable->y);
-
- return Success;
-}
-
-/* Major version controls available requests */
-static const int version_requests[] = {
- X_DamageQueryVersion, /* before client sends QueryVersion */
- X_DamageAdd, /* Version 1 */
-};
-
-#define NUM_VERSION_REQUESTS (sizeof (version_requests) / sizeof (version_requests[0]))
-
-static int (*ProcDamageVector[XDamageNumberRequests])(ClientPtr) = {
-/*************** Version 1 ******************/
- ProcDamageQueryVersion,
- ProcDamageCreate,
- ProcDamageDestroy,
- ProcDamageSubtract,
-/*************** Version 1.1 ****************/
- ProcDamageAdd,
-};
-
-
-static int
-ProcDamageDispatch (ClientPtr client)
-{
- REQUEST(xDamageReq);
- DamageClientPtr pDamageClient = GetDamageClient (client);
-
- if (pDamageClient->major_version >= NUM_VERSION_REQUESTS)
- return BadRequest;
- if (stuff->damageReqType > version_requests[pDamageClient->major_version])
- return BadRequest;
- return (*ProcDamageVector[stuff->damageReqType]) (client);
-}
-
-static int
-SProcDamageQueryVersion(ClientPtr client)
-{
- register int n;
- REQUEST(xDamageQueryVersionReq);
-
- swaps(&stuff->length, n);
- REQUEST_SIZE_MATCH(xDamageQueryVersionReq);
- swapl(&stuff->majorVersion, n);
- swapl(&stuff->minorVersion, n);
- return (*ProcDamageVector[stuff->damageReqType]) (client);
-}
-
-static int
-SProcDamageCreate (ClientPtr client)
-{
- register int n;
- REQUEST(xDamageCreateReq);
-
- swaps (&stuff->length, n);
- REQUEST_SIZE_MATCH(xDamageCreateReq);
- swapl (&stuff->damage, n);
- swapl (&stuff->drawable, n);
- return (*ProcDamageVector[stuff->damageReqType]) (client);
-}
-
-static int
-SProcDamageDestroy (ClientPtr client)
-{
- register int n;
- REQUEST(xDamageDestroyReq);
-
- swaps (&stuff->length, n);
- REQUEST_SIZE_MATCH(xDamageDestroyReq);
- swapl (&stuff->damage, n);
- return (*ProcDamageVector[stuff->damageReqType]) (client);
-}
-
-static int
-SProcDamageSubtract (ClientPtr client)
-{
- register int n;
- REQUEST(xDamageSubtractReq);
-
- swaps (&stuff->length, n);
- REQUEST_SIZE_MATCH(xDamageSubtractReq);
- swapl (&stuff->damage, n);
- swapl (&stuff->repair, n);
- swapl (&stuff->parts, n);
- return (*ProcDamageVector[stuff->damageReqType]) (client);
-}
-
-static int
-SProcDamageAdd (ClientPtr client)
-{
- register int n;
- REQUEST(xDamageAddReq);
-
- swaps (&stuff->length, n);
- REQUEST_SIZE_MATCH(xDamageSubtractReq);
- swapl (&stuff->drawable, n);
- swapl (&stuff->region, n);
- return (*ProcDamageVector[stuff->damageReqType]) (client);
-}
-
-static int (*SProcDamageVector[XDamageNumberRequests])(ClientPtr) = {
-/*************** Version 1 ******************/
- SProcDamageQueryVersion,
- SProcDamageCreate,
- SProcDamageDestroy,
- SProcDamageSubtract,
-/*************** Version 1.1 ****************/
- SProcDamageAdd,
-};
-
-static int
-SProcDamageDispatch (ClientPtr client)
-{
- REQUEST(xDamageReq);
- if (stuff->damageReqType >= XDamageNumberRequests)
- return BadRequest;
- return (*SProcDamageVector[stuff->damageReqType]) (client);
-}
-
-static void
-DamageClientCallback (CallbackListPtr *list,
- pointer closure,
- pointer data)
-{
- NewClientInfoRec *clientinfo = (NewClientInfoRec *) data;
- ClientPtr pClient = clientinfo->client;
- DamageClientPtr pDamageClient = GetDamageClient (pClient);
-
- pDamageClient->critical = 0;
- pDamageClient->major_version = 0;
- pDamageClient->minor_version = 0;
-}
-
-/*ARGSUSED*/
-static void
-DamageResetProc (ExtensionEntry *extEntry)
-{
- DeleteCallback (&ClientStateCallback, DamageClientCallback, 0);
-}
-
-static int
-FreeDamageExt (pointer value, XID did)
-{
- DamageExtPtr pDamageExt = (DamageExtPtr) value;
-
- /*
- * Get rid of the resource table entry hanging from the window id
- */
- pDamageExt->id = 0;
- if (WindowDrawable(pDamageExt->pDrawable->type))
- FreeResourceByType (pDamageExt->pDrawable->id, DamageExtWinType, TRUE);
- if (pDamageExt->pDamage)
- {
- DamageUnregister (pDamageExt->pDrawable, pDamageExt->pDamage);
- DamageDestroy (pDamageExt->pDamage);
- }
- free(pDamageExt);
- return Success;
-}
-
-static int
-FreeDamageExtWin (pointer value, XID wid)
-{
- DamageExtPtr pDamageExt = (DamageExtPtr) value;
-
- if (pDamageExt->id)
- FreeResource (pDamageExt->id, RT_NONE);
- return Success;
-}
-
-static void
-SDamageNotifyEvent (xDamageNotifyEvent *from,
- xDamageNotifyEvent *to)
-{
- to->type = from->type;
- cpswaps (from->sequenceNumber, to->sequenceNumber);
- cpswapl (from->drawable, to->drawable);
- cpswapl (from->damage, to->damage);
- cpswaps (from->area.x, to->area.x);
- cpswaps (from->area.y, to->area.y);
- cpswaps (from->area.width, to->area.width);
- cpswaps (from->area.height, to->area.height);
- cpswaps (from->geometry.x, to->geometry.x);
- cpswaps (from->geometry.y, to->geometry.y);
- cpswaps (from->geometry.width, to->geometry.width);
- cpswaps (from->geometry.height, to->geometry.height);
-}
-
-void
-DamageExtensionInit(void)
-{
- ExtensionEntry *extEntry;
- int s;
-
- for (s = 0; s < screenInfo.numScreens; s++)
- DamageSetup (screenInfo.screens[s]);
-
- DamageExtType = CreateNewResourceType (FreeDamageExt, "DamageExt");
- if (!DamageExtType)
- return;
-
- DamageExtWinType = CreateNewResourceType (FreeDamageExtWin, "DamageExtWin");
- if (!DamageExtWinType)
- return;
-
- if (!dixRegisterPrivateKey(&DamageClientPrivateKeyRec, PRIVATE_CLIENT, sizeof (DamageClientRec)))
- return;
-
- if (!AddCallback (&ClientStateCallback, DamageClientCallback, 0))
- return;
-
- if ((extEntry = AddExtension(DAMAGE_NAME, XDamageNumberEvents,
- XDamageNumberErrors,
- ProcDamageDispatch, SProcDamageDispatch,
- DamageResetProc, StandardMinorOpcode)) != 0)
- {
- DamageReqCode = (unsigned char)extEntry->base;
- DamageEventBase = extEntry->eventBase;
- EventSwapVector[DamageEventBase + XDamageNotify] =
- (EventSwapPtr) SDamageNotifyEvent;
- SetResourceTypeErrorValue(DamageExtType, extEntry->errorBase + BadDamage);
- }
-}
+/* + * Copyright © 2002 Keith Packard + * + * Permission to use, copy, modify, distribute, and sell this software and its + * documentation for any purpose is hereby granted without fee, provided that + * the above copyright notice appear in all copies and that both that + * copyright notice and this permission notice appear in supporting + * documentation, and that the name of Keith Packard not be used in + * advertising or publicity pertaining to distribution of the software without + * specific, written prior permission. Keith Packard makes no + * representations about the suitability of this software for any purpose. It + * is provided "as is" without express or implied warranty. + * + * KEITH PACKARD DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, + * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO + * EVENT SHALL KEITH PACKARD BE LIABLE FOR ANY SPECIAL, INDIRECT OR + * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, + * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + +#ifdef HAVE_DIX_CONFIG_H +#include <dix-config.h> +#endif + +#include "damageextint.h" +#include "protocol-versions.h" + +static unsigned char DamageReqCode; +static int DamageEventBase; +static RESTYPE DamageExtType; +static RESTYPE DamageExtWinType; + +static DevPrivateKeyRec DamageClientPrivateKeyRec; +#define DamageClientPrivateKey (&DamageClientPrivateKeyRec) + +static void +DamageExtNotify (DamageExtPtr pDamageExt, BoxPtr pBoxes, int nBoxes) +{ + ClientPtr pClient = pDamageExt->pClient; + DamageClientPtr pDamageClient = GetDamageClient (pClient); + DrawablePtr pDrawable = pDamageExt->pDrawable; + xDamageNotifyEvent ev; + int i; + + UpdateCurrentTimeIf (); + ev.type = DamageEventBase + XDamageNotify; + ev.level = pDamageExt->level; + ev.drawable = pDamageExt->drawable; + ev.damage = pDamageExt->id; + ev.timestamp = currentTime.milliseconds; + ev.geometry.x = pDrawable->x; + ev.geometry.y = pDrawable->y; + ev.geometry.width = pDrawable->width; + ev.geometry.height = pDrawable->height; + if (pBoxes) + { + for (i = 0; i < nBoxes; i++) + { + ev.level = pDamageExt->level; + if (i < nBoxes - 1) + ev.level |= DamageNotifyMore; + ev.area.x = pBoxes[i].x1; + ev.area.y = pBoxes[i].y1; + ev.area.width = pBoxes[i].x2 - pBoxes[i].x1; + ev.area.height = pBoxes[i].y2 - pBoxes[i].y1; + WriteEventsToClient (pClient, 1, (xEvent *) &ev); + } + } + else + { + ev.area.x = 0; + ev.area.y = 0; + ev.area.width = pDrawable->width; + ev.area.height = pDrawable->height; + WriteEventsToClient (pClient, 1, (xEvent *) &ev); + } + /* Composite extension marks clients with manual Subwindows as critical */ + if (pDamageClient->critical > 0) + { + SetCriticalOutputPending (); + pClient->smart_priority = SMART_MAX_PRIORITY; + } +} + +static void +DamageExtReport (DamagePtr pDamage, RegionPtr pRegion, void *closure) +{ + DamageExtPtr pDamageExt = closure; + + switch (pDamageExt->level) { + case DamageReportRawRegion: + case DamageReportDeltaRegion: + DamageExtNotify (pDamageExt, RegionRects(pRegion), RegionNumRects(pRegion)); + break; + case DamageReportBoundingBox: + DamageExtNotify (pDamageExt, RegionExtents(pRegion), 1); + break; + case DamageReportNonEmpty: + DamageExtNotify (pDamageExt, NullBox, 0); + break; + case DamageReportNone: + break; + } +} + +static void +DamageExtDestroy (DamagePtr pDamage, void *closure) +{ + DamageExtPtr pDamageExt = closure; + + pDamageExt->pDamage = 0; + if (pDamageExt->id) + FreeResource (pDamageExt->id, RT_NONE); +} + +void +DamageExtSetCritical (ClientPtr pClient, Bool critical) +{ + DamageClientPtr pDamageClient = GetDamageClient (pClient); + + if (pDamageClient) + pDamageClient->critical += critical ? 1 : -1; +} + +static int +ProcDamageQueryVersion(ClientPtr client) +{ + DamageClientPtr pDamageClient = GetDamageClient (client); + xDamageQueryVersionReply rep; + register int n; + REQUEST(xDamageQueryVersionReq); + + REQUEST_SIZE_MATCH(xDamageQueryVersionReq); + rep.type = X_Reply; + rep.length = 0; + rep.sequenceNumber = client->sequence; + if (stuff->majorVersion < SERVER_DAMAGE_MAJOR_VERSION) { + rep.majorVersion = stuff->majorVersion; + rep.minorVersion = stuff->minorVersion; + } else { + rep.majorVersion = SERVER_DAMAGE_MAJOR_VERSION; + if (stuff->majorVersion == SERVER_DAMAGE_MAJOR_VERSION && + stuff->minorVersion < SERVER_DAMAGE_MINOR_VERSION) + rep.minorVersion = stuff->minorVersion; + else + rep.minorVersion = SERVER_DAMAGE_MINOR_VERSION; + } + pDamageClient->major_version = rep.majorVersion; + pDamageClient->minor_version = rep.minorVersion; + if (client->swapped) { + swaps(&rep.sequenceNumber, n); + swapl(&rep.length, n); + swapl(&rep.majorVersion, n); + swapl(&rep.minorVersion, n); + } + WriteToClient(client, sizeof(xDamageQueryVersionReply), (char *)&rep); + return Success; +} + +static int +ProcDamageCreate (ClientPtr client) +{ + DrawablePtr pDrawable; + DamageExtPtr pDamageExt; + DamageReportLevel level; + RegionPtr pRegion; + int rc; + + REQUEST(xDamageCreateReq); + + REQUEST_SIZE_MATCH(xDamageCreateReq); + LEGAL_NEW_RESOURCE(stuff->damage, client); + rc = dixLookupDrawable(&pDrawable, stuff->drawable, client, 0, + DixGetAttrAccess|DixReadAccess); + if (rc != Success) + return rc; + + switch (stuff->level) { + case XDamageReportRawRectangles: + level = DamageReportRawRegion; + break; + case XDamageReportDeltaRectangles: + level = DamageReportDeltaRegion; + break; + case XDamageReportBoundingBox: + level = DamageReportBoundingBox; + break; + case XDamageReportNonEmpty: + level = DamageReportNonEmpty; + break; + default: + client->errorValue = stuff->level; + return BadValue; + } + + pDamageExt = malloc(sizeof (DamageExtRec)); + if (!pDamageExt) + return BadAlloc; + pDamageExt->id = stuff->damage; + pDamageExt->drawable = stuff->drawable; + pDamageExt->pDrawable = pDrawable; + pDamageExt->level = level; + pDamageExt->pClient = client; + pDamageExt->pDamage = DamageCreate (DamageExtReport, + DamageExtDestroy, + level, + FALSE, + pDrawable->pScreen, + pDamageExt); + if (!pDamageExt->pDamage) + { + free(pDamageExt); + return BadAlloc; + } + if (!AddResource (stuff->damage, DamageExtType, (pointer) pDamageExt)) + return BadAlloc; + + DamageSetReportAfterOp (pDamageExt->pDamage, TRUE); + DamageRegister (pDamageExt->pDrawable, pDamageExt->pDamage); + + if (pDrawable->type == DRAWABLE_WINDOW) + { + pRegion = &((WindowPtr) pDrawable)->borderClip; + DamageReportDamage(pDamageExt->pDamage, pRegion); + } + + return Success; +} + +static int +ProcDamageDestroy (ClientPtr client) +{ + REQUEST(xDamageDestroyReq); + DamageExtPtr pDamageExt; + + REQUEST_SIZE_MATCH(xDamageDestroyReq); + VERIFY_DAMAGEEXT(pDamageExt, stuff->damage, client, DixWriteAccess); + FreeResource (stuff->damage, RT_NONE); + return Success; +} + +static int +ProcDamageSubtract (ClientPtr client) +{ + REQUEST(xDamageSubtractReq); + DamageExtPtr pDamageExt; + RegionPtr pRepair; + RegionPtr pParts; + + REQUEST_SIZE_MATCH(xDamageSubtractReq); + VERIFY_DAMAGEEXT(pDamageExt, stuff->damage, client, DixWriteAccess); + VERIFY_REGION_OR_NONE(pRepair, stuff->repair, client, DixWriteAccess); + VERIFY_REGION_OR_NONE(pParts, stuff->parts, client, DixWriteAccess); + + if (pDamageExt->level != DamageReportRawRegion) + { + DamagePtr pDamage = pDamageExt->pDamage; + if (pRepair) + { + if (pParts) + RegionIntersect(pParts, DamageRegion (pDamage), pRepair); + if (DamageSubtract (pDamage, pRepair)) + DamageExtReport (pDamage, DamageRegion (pDamage), (void *) pDamageExt); + } + else + { + if (pParts) + RegionCopy(pParts, DamageRegion (pDamage)); + DamageEmpty (pDamage); + } + } + return Success; +} + +static int +ProcDamageAdd (ClientPtr client) +{ + REQUEST(xDamageAddReq); + DrawablePtr pDrawable; + RegionPtr pRegion; + int rc; + + REQUEST_SIZE_MATCH(xDamageAddReq); + VERIFY_REGION(pRegion, stuff->region, client, DixWriteAccess); + rc = dixLookupDrawable(&pDrawable, stuff->drawable, client, 0, + DixWriteAccess); + if (rc != Success) + return rc; + + /* The region is relative to the drawable origin, so translate it out to + * screen coordinates like damage expects. + */ + RegionTranslate(pRegion, pDrawable->x, pDrawable->y); + DamageDamageRegion(pDrawable, pRegion); + RegionTranslate(pRegion, -pDrawable->x, -pDrawable->y); + + return Success; +} + +/* Major version controls available requests */ +static const int version_requests[] = { + X_DamageQueryVersion, /* before client sends QueryVersion */ + X_DamageAdd, /* Version 1 */ +}; + +#define NUM_VERSION_REQUESTS (sizeof (version_requests) / sizeof (version_requests[0])) + +static int (*ProcDamageVector[XDamageNumberRequests])(ClientPtr) = { +/*************** Version 1 ******************/ + ProcDamageQueryVersion, + ProcDamageCreate, + ProcDamageDestroy, + ProcDamageSubtract, +/*************** Version 1.1 ****************/ + ProcDamageAdd, +}; + + +static int +ProcDamageDispatch (ClientPtr client) +{ + REQUEST(xDamageReq); + DamageClientPtr pDamageClient = GetDamageClient (client); + + if (pDamageClient->major_version >= NUM_VERSION_REQUESTS) + return BadRequest; + if (stuff->damageReqType > version_requests[pDamageClient->major_version]) + return BadRequest; + return (*ProcDamageVector[stuff->damageReqType]) (client); +} + +static int +SProcDamageQueryVersion(ClientPtr client) +{ + register int n; + REQUEST(xDamageQueryVersionReq); + + swaps(&stuff->length, n); + REQUEST_SIZE_MATCH(xDamageQueryVersionReq); + swapl(&stuff->majorVersion, n); + swapl(&stuff->minorVersion, n); + return (*ProcDamageVector[stuff->damageReqType]) (client); +} + +static int +SProcDamageCreate (ClientPtr client) +{ + register int n; + REQUEST(xDamageCreateReq); + + swaps (&stuff->length, n); + REQUEST_SIZE_MATCH(xDamageCreateReq); + swapl (&stuff->damage, n); + swapl (&stuff->drawable, n); + return (*ProcDamageVector[stuff->damageReqType]) (client); +} + +static int +SProcDamageDestroy (ClientPtr client) +{ + register int n; + REQUEST(xDamageDestroyReq); + + swaps (&stuff->length, n); + REQUEST_SIZE_MATCH(xDamageDestroyReq); + swapl (&stuff->damage, n); + return (*ProcDamageVector[stuff->damageReqType]) (client); +} + +static int +SProcDamageSubtract (ClientPtr client) +{ + register int n; + REQUEST(xDamageSubtractReq); + + swaps (&stuff->length, n); + REQUEST_SIZE_MATCH(xDamageSubtractReq); + swapl (&stuff->damage, n); + swapl (&stuff->repair, n); + swapl (&stuff->parts, n); + return (*ProcDamageVector[stuff->damageReqType]) (client); +} + +static int +SProcDamageAdd (ClientPtr client) +{ + register int n; + REQUEST(xDamageAddReq); + + swaps (&stuff->length, n); + REQUEST_SIZE_MATCH(xDamageSubtractReq); + swapl (&stuff->drawable, n); + swapl (&stuff->region, n); + return (*ProcDamageVector[stuff->damageReqType]) (client); +} + +static int (*SProcDamageVector[XDamageNumberRequests])(ClientPtr) = { +/*************** Version 1 ******************/ + SProcDamageQueryVersion, + SProcDamageCreate, + SProcDamageDestroy, + SProcDamageSubtract, +/*************** Version 1.1 ****************/ + SProcDamageAdd, +}; + +static int +SProcDamageDispatch (ClientPtr client) +{ + REQUEST(xDamageReq); + if (stuff->damageReqType >= XDamageNumberRequests) + return BadRequest; + return (*SProcDamageVector[stuff->damageReqType]) (client); +} + +static void +DamageClientCallback (CallbackListPtr *list, + pointer closure, + pointer data) +{ + NewClientInfoRec *clientinfo = (NewClientInfoRec *) data; + ClientPtr pClient = clientinfo->client; + DamageClientPtr pDamageClient = GetDamageClient (pClient); + + pDamageClient->critical = 0; + pDamageClient->major_version = 0; + pDamageClient->minor_version = 0; +} + +/*ARGSUSED*/ +static void +DamageResetProc (ExtensionEntry *extEntry) +{ + DeleteCallback (&ClientStateCallback, DamageClientCallback, 0); +} + +static int +FreeDamageExt (pointer value, XID did) +{ + DamageExtPtr pDamageExt = (DamageExtPtr) value; + + /* + * Get rid of the resource table entry hanging from the window id + */ + pDamageExt->id = 0; + if (WindowDrawable(pDamageExt->pDrawable->type)) + FreeResourceByType (pDamageExt->pDrawable->id, DamageExtWinType, TRUE); + if (pDamageExt->pDamage) + { + DamageUnregister (pDamageExt->pDrawable, pDamageExt->pDamage); + DamageDestroy (pDamageExt->pDamage); + } + free(pDamageExt); + return Success; +} + +static int +FreeDamageExtWin (pointer value, XID wid) +{ + DamageExtPtr pDamageExt = (DamageExtPtr) value; + + if (pDamageExt->id) + FreeResource (pDamageExt->id, RT_NONE); + return Success; +} + +static void +SDamageNotifyEvent (xDamageNotifyEvent *from, + xDamageNotifyEvent *to) +{ + to->type = from->type; + cpswaps (from->sequenceNumber, to->sequenceNumber); + cpswapl (from->drawable, to->drawable); + cpswapl (from->damage, to->damage); + cpswaps (from->area.x, to->area.x); + cpswaps (from->area.y, to->area.y); + cpswaps (from->area.width, to->area.width); + cpswaps (from->area.height, to->area.height); + cpswaps (from->geometry.x, to->geometry.x); + cpswaps (from->geometry.y, to->geometry.y); + cpswaps (from->geometry.width, to->geometry.width); + cpswaps (from->geometry.height, to->geometry.height); +} + +void +DamageExtensionInit(void) +{ + ExtensionEntry *extEntry; + int s; + + for (s = 0; s < screenInfo.numScreens; s++) + DamageSetup (screenInfo.screens[s]); + + DamageExtType = CreateNewResourceType (FreeDamageExt, "DamageExt"); + if (!DamageExtType) + return; + + DamageExtWinType = CreateNewResourceType (FreeDamageExtWin, "DamageExtWin"); + if (!DamageExtWinType) + return; + + if (!dixRegisterPrivateKey(&DamageClientPrivateKeyRec, PRIVATE_CLIENT, sizeof (DamageClientRec))) + return; + + if (!AddCallback (&ClientStateCallback, DamageClientCallback, 0)) + return; + + if ((extEntry = AddExtension(DAMAGE_NAME, XDamageNumberEvents, + XDamageNumberErrors, + ProcDamageDispatch, SProcDamageDispatch, + DamageResetProc, StandardMinorOpcode)) != 0) + { + DamageReqCode = (unsigned char)extEntry->base; + DamageEventBase = extEntry->eventBase; + EventSwapVector[DamageEventBase + XDamageNotify] = + (EventSwapPtr) SDamageNotifyEvent; + SetResourceTypeErrorValue(DamageExtType, extEntry->errorBase + BadDamage); + } +} diff --git a/xorg-server/dix/cursor.c b/xorg-server/dix/cursor.c index acd118a1c..c191c1e88 100644 --- a/xorg-server/dix/cursor.c +++ b/xorg-server/dix/cursor.c @@ -1,515 +1,512 @@ -/***********************************************************
-
-Copyright 1987, 1998 The Open Group
-
-Permission to use, copy, modify, distribute, and sell this software and its
-documentation for any purpose is hereby granted without fee, provided that
-the above copyright notice appear in all copies and that both that
-copyright notice and this permission notice appear in supporting
-documentation.
-
-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
-OPEN GROUP 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.
-
-Except as contained in this notice, the name of The Open Group shall not be
-used in advertising or otherwise to promote the sale, use or other dealings
-in this Software without prior written authorization from The Open Group.
-
-
-Copyright 1987 by Digital Equipment Corporation, Maynard, Massachusetts.
-
- All Rights Reserved
-
-Permission to use, copy, modify, and distribute this software and its
-documentation for any purpose and without fee is hereby granted,
-provided that the above copyright notice appear in all copies and that
-both that copyright notice and this permission notice appear in
-supporting documentation, and that the name of Digital not be
-used in advertising or publicity pertaining to distribution of the
-software without specific, written prior permission.
-
-DIGITAL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
-ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL
-DIGITAL BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR
-ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
-WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
-ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
-SOFTWARE.
-
-******************************************************************/
-
-
-
-#ifdef HAVE_DIX_CONFIG_H
-#include <dix-config.h>
-#endif
-
-#include <X11/X.h>
-#include <X11/Xmd.h>
-#include "servermd.h"
-#include "scrnintstr.h"
-#include "dixstruct.h"
-#include "cursorstr.h"
-#include "dixfontstr.h"
-#include "opaque.h"
-#include "inputstr.h"
-#include "xace.h"
-
-typedef struct _GlyphShare {
- FontPtr font;
- unsigned short sourceChar;
- unsigned short maskChar;
- CursorBitsPtr bits;
- struct _GlyphShare *next;
-} GlyphShare, *GlyphSharePtr;
-
-static GlyphSharePtr sharedGlyphs = (GlyphSharePtr)NULL;
-
-DevPrivateKeyRec cursorScreenDevPriv[MAXSCREENS];
-
-#ifdef XFIXES
-static CARD32 cursorSerial;
-#endif
-
-static void
-FreeCursorBits(CursorBitsPtr bits)
-{
- if (--bits->refcnt > 0)
- return;
- free(bits->source);
- free(bits->mask);
-#ifdef ARGB_CURSOR
- free(bits->argb);
-#endif
- dixFiniPrivates(bits, PRIVATE_CURSOR_BITS);
- if (bits->refcnt == 0)
- {
- GlyphSharePtr *prev, this;
-
- for (prev = &sharedGlyphs;
- (this = *prev) && (this->bits != bits);
- prev = &this->next)
- ;
- if (this)
- {
- *prev = this->next;
- CloseFont(this->font, (Font)0);
- free(this);
- }
- free(bits);
- }
-}
-
-/**
- * To be called indirectly by DeleteResource; must use exactly two args.
- *
- * \param value must conform to DeleteType
- */
-int
-FreeCursor(pointer value, XID cid)
-{
- int nscr;
- CursorPtr pCurs = (CursorPtr)value;
-
- ScreenPtr pscr;
- DeviceIntPtr pDev = NULL; /* unused anyway */
-
- if ( --pCurs->refcnt != 0)
- return Success;
-
- for (nscr = 0; nscr < screenInfo.numScreens; nscr++)
- {
- pscr = screenInfo.screens[nscr];
- (void)( *pscr->UnrealizeCursor)(pDev, pscr, pCurs);
- }
- FreeCursorBits(pCurs->bits);
- dixFiniPrivates(pCurs, PRIVATE_CURSOR);
- free( pCurs);
- return Success;
-}
-
-
-/*
- * We check for empty cursors so that we won't have to display them
- */
-static void
-CheckForEmptyMask(CursorBitsPtr bits)
-{
- unsigned char *msk = bits->mask;
- int n = BitmapBytePad(bits->width) * bits->height;
-
- bits->emptyMask = FALSE;
- while(n--)
- if(*(msk++) != 0) return;
-#ifdef ARGB_CURSOR
- if (bits->argb)
- {
- CARD32 *argb = bits->argb;
- int n = bits->width * bits->height;
- while (n--)
- if (*argb++ & 0xff000000) return;
- }
-#endif
- bits->emptyMask = TRUE;
-}
-
-/**
- * realize the cursor for every screen. Do not change the refcnt, this will be
- * changed when ChangeToCursor actually changes the sprite.
- *
- * @return Success if all cursors realize on all screens, BadAlloc if realize
- * failed for a device on a given screen.
- */
-static int
-RealizeCursorAllScreens(CursorPtr pCurs)
-{
- DeviceIntPtr pDev;
- ScreenPtr pscr;
- int nscr;
-
- for (nscr = 0; nscr < screenInfo.numScreens; nscr++)
- {
- pscr = screenInfo.screens[nscr];
- for (pDev = inputInfo.devices; pDev; pDev = pDev->next)
- {
- if (DevHasCursor(pDev))
- {
- if (!( *pscr->RealizeCursor)(pDev, pscr, pCurs))
- {
- /* Realize failed for device pDev on screen pscr.
- * We have to assume that for all devices before, realize
- * worked. We need to rollback all devices so far on the
- * current screen and then all devices on previous
- * screens.
- */
- DeviceIntPtr pDevIt = inputInfo.devices; /*dev iterator*/
- while(pDevIt && pDevIt != pDev)
- {
- if (DevHasCursor(pDevIt))
- ( *pscr->UnrealizeCursor)(pDevIt, pscr, pCurs);
- pDevIt = pDevIt->next;
- }
- while (--nscr >= 0)
- {
- pscr = screenInfo.screens[nscr];
- /* now unrealize all devices on previous screens */
- pDevIt = inputInfo.devices;
- while (pDevIt)
- {
- if (DevHasCursor(pDevIt))
- ( *pscr->UnrealizeCursor)(pDevIt, pscr, pCurs);
- pDevIt = pDevIt->next;
- }
- ( *pscr->UnrealizeCursor)(pDev, pscr, pCurs);
- }
- return BadAlloc;
- }
- }
- }
- }
-
- return Success;
-}
-
-
-/**
- * does nothing about the resource table, just creates the data structure.
- * does not copy the src and mask bits
- *
- * \param psrcbits server-defined padding
- * \param pmaskbits server-defined padding
- * \param argb no padding
- */
-int
-AllocARGBCursor(unsigned char *psrcbits, unsigned char *pmaskbits,
- CARD32 *argb, CursorMetricPtr cm,
- unsigned foreRed, unsigned foreGreen, unsigned foreBlue,
- unsigned backRed, unsigned backGreen, unsigned backBlue,
- CursorPtr *ppCurs, ClientPtr client, XID cid)
-{
- CursorBitsPtr bits;
- CursorPtr pCurs;
- int rc;
-
- *ppCurs = NULL;
- pCurs = (CursorPtr)calloc(CURSOR_REC_SIZE + CURSOR_BITS_SIZE, 1);
- if (!pCurs)
- {
- free(psrcbits);
- free(pmaskbits);
- return BadAlloc;
- }
- bits = (CursorBitsPtr)((char *)pCurs + CURSOR_REC_SIZE);
- dixInitPrivates(pCurs, pCurs + 1, PRIVATE_CURSOR);
- dixInitPrivates(bits, bits + 1, PRIVATE_CURSOR_BITS)
- bits->source = psrcbits;
- bits->mask = pmaskbits;
-#ifdef ARGB_CURSOR
- bits->argb = argb;
-#endif
- bits->width = cm->width;
- bits->height = cm->height;
- bits->xhot = cm->xhot;
- bits->yhot = cm->yhot;
- pCurs->refcnt = 1;
- bits->refcnt = -1;
- CheckForEmptyMask(bits);
- pCurs->bits = bits;
-#ifdef XFIXES
- pCurs->serialNumber = ++cursorSerial;
- pCurs->name = None;
-#endif
-
- pCurs->foreRed = foreRed;
- pCurs->foreGreen = foreGreen;
- pCurs->foreBlue = foreBlue;
-
- pCurs->backRed = backRed;
- pCurs->backGreen = backGreen;
- pCurs->backBlue = backBlue;
-
- pCurs->id = cid;
-
- /* security creation/labeling check */
- rc = XaceHook(XACE_RESOURCE_ACCESS, client, cid, RT_CURSOR,
- pCurs, RT_NONE, NULL, DixCreateAccess);
- if (rc != Success)
- goto error;
-
- rc = RealizeCursorAllScreens(pCurs);
- if (rc != Success)
- goto error;
-
- *ppCurs = pCurs;
- return Success;
-
-error:
- FreeCursorBits(bits);
- dixFiniPrivates(pCurs, PRIVATE_CURSOR);
- free(pCurs);
-
- return rc;
-}
-
-int
-AllocGlyphCursor(Font source, unsigned sourceChar, Font mask, unsigned maskChar,
- unsigned foreRed, unsigned foreGreen, unsigned foreBlue,
- unsigned backRed, unsigned backGreen, unsigned backBlue,
- CursorPtr *ppCurs, ClientPtr client, XID cid)
-{
- FontPtr sourcefont, maskfont;
- unsigned char *srcbits;
- unsigned char *mskbits;
- CursorMetricRec cm;
- int rc;
- CursorBitsPtr bits;
- CursorPtr pCurs;
- GlyphSharePtr pShare;
-
- rc = dixLookupResourceByType((pointer *)&sourcefont, source, RT_FONT, client,
- DixUseAccess);
- if (rc != Success)
- {
- client->errorValue = source;
- return rc;
- }
- rc = dixLookupResourceByType((pointer *)&maskfont, mask, RT_FONT, client,
- DixUseAccess);
- if (rc != Success && mask != None)
- {
- client->errorValue = mask;
- return rc;
- }
- if (sourcefont != maskfont)
- pShare = (GlyphSharePtr)NULL;
- else
- {
- for (pShare = sharedGlyphs;
- pShare &&
- ((pShare->font != sourcefont) ||
- (pShare->sourceChar != sourceChar) ||
- (pShare->maskChar != maskChar));
- pShare = pShare->next)
- ;
- }
- if (pShare)
- {
- pCurs = (CursorPtr)calloc(CURSOR_REC_SIZE, 1);
- if (!pCurs)
- return BadAlloc;
- dixInitPrivates(pCurs, pCurs + 1, PRIVATE_CURSOR);
- bits = pShare->bits;
- bits->refcnt++;
- }
- else
- {
- if (!CursorMetricsFromGlyph(sourcefont, sourceChar, &cm))
- {
- client->errorValue = sourceChar;
- return BadValue;
- }
- if (!maskfont)
- {
- long n;
- unsigned char *mskptr;
-
- n = BitmapBytePad(cm.width)*(long)cm.height;
- mskptr = mskbits = malloc(n);
- if (!mskptr)
- return BadAlloc;
- while (--n >= 0)
- *mskptr++ = ~0;
- }
- else
- {
- if (!CursorMetricsFromGlyph(maskfont, maskChar, &cm))
- {
- client->errorValue = maskChar;
- return BadValue;
- }
- if ((rc = ServerBitsFromGlyph(maskfont, maskChar, &cm, &mskbits)))
- return rc;
- }
- if ((rc = ServerBitsFromGlyph(sourcefont, sourceChar, &cm, &srcbits)))
- {
- free(mskbits);
- return rc;
- }
- if (sourcefont != maskfont)
- {
- pCurs =
- (CursorPtr)calloc(CURSOR_REC_SIZE + CURSOR_BITS_SIZE, 1);
- if (pCurs)
- bits = (CursorBitsPtr)((char *)pCurs + CURSOR_REC_SIZE);
- else
- bits = (CursorBitsPtr)NULL;
- }
- else
- {
- pCurs = (CursorPtr)calloc(CURSOR_REC_SIZE, 1);
- if (pCurs)
- bits = (CursorBitsPtr)calloc(CURSOR_BITS_SIZE, 1);
- else
- bits = (CursorBitsPtr)NULL;
- }
- if (!bits)
- {
- free(pCurs);
- free(mskbits);
- free(srcbits);
- return BadAlloc;
- }
- dixInitPrivates(pCurs, pCurs + 1, PRIVATE_CURSOR);
- dixInitPrivates(bits, bits + 1, PRIVATE_CURSOR_BITS);
- bits->source = srcbits;
- bits->mask = mskbits;
-#ifdef ARGB_CURSOR
- bits->argb = 0;
-#endif
- bits->width = cm.width;
- bits->height = cm.height;
- bits->xhot = cm.xhot;
- bits->yhot = cm.yhot;
- if (sourcefont != maskfont)
- bits->refcnt = -1;
- else
- {
- bits->refcnt = 1;
- pShare = malloc(sizeof(GlyphShare));
- if (!pShare)
- {
- FreeCursorBits(bits);
- return BadAlloc;
- }
- pShare->font = sourcefont;
- sourcefont->refcnt++;
- pShare->sourceChar = sourceChar;
- pShare->maskChar = maskChar;
- pShare->bits = bits;
- pShare->next = sharedGlyphs;
- sharedGlyphs = pShare;
- }
- }
-
- CheckForEmptyMask(bits);
- pCurs->bits = bits;
- pCurs->refcnt = 1;
-#ifdef XFIXES
- pCurs->serialNumber = ++cursorSerial;
- pCurs->name = None;
-#endif
-
- pCurs->foreRed = foreRed;
- pCurs->foreGreen = foreGreen;
- pCurs->foreBlue = foreBlue;
-
- pCurs->backRed = backRed;
- pCurs->backGreen = backGreen;
- pCurs->backBlue = backBlue;
-
- pCurs->id = cid;
-
- /* security creation/labeling check */
- rc = XaceHook(XACE_RESOURCE_ACCESS, client, cid, RT_CURSOR,
- pCurs, RT_NONE, NULL, DixCreateAccess);
- if (rc != Success)
- goto error;
-
- rc = RealizeCursorAllScreens(pCurs);
- if (rc != Success)
- goto error;
-
- *ppCurs = pCurs;
- return Success;
-
-error:
- FreeCursorBits(bits);
- dixFiniPrivates(pCurs, PRIVATE_CURSOR);
- free(pCurs);
-
- return rc;
-}
-
-/** CreateRootCursor
- *
- * look up the name of a font
- * open the font
- * add the font to the resource table
- * make a cursor from the glyphs
- * add the cursor to the resource table
- *************************************************************/
-
-CursorPtr
-CreateRootCursor(char *unused1, unsigned int unused2)
-{
- CursorPtr curs;
- FontPtr cursorfont;
- int err;
- XID fontID;
-
- fontID = FakeClientID(0);
- err = OpenFont(serverClient, fontID, FontLoadAll | FontOpenSync,
- (unsigned)strlen(defaultCursorFont), defaultCursorFont);
- if (err != Success)
- return NullCursor;
-
- err = dixLookupResourceByType((pointer *)&cursorfont, fontID, RT_FONT,
- serverClient, DixReadAccess);
- if (err != Success)
- return NullCursor;
- if (AllocGlyphCursor(fontID, 0, fontID, 1, 0, 0, 0, ~0, ~0, ~0,
- &curs, serverClient, (XID)0) != Success)
- return NullCursor;
-
- if (!AddResource(FakeClientID(0), RT_CURSOR, (pointer)curs))
- return NullCursor;
-
- return curs;
-}
+/*********************************************************** + +Copyright 1987, 1998 The Open Group + +Permission to use, copy, modify, distribute, and sell this software and its +documentation for any purpose is hereby granted without fee, provided that +the above copyright notice appear in all copies and that both that +copyright notice and this permission notice appear in supporting +documentation. + +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 +OPEN GROUP 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. + +Except as contained in this notice, the name of The Open Group shall not be +used in advertising or otherwise to promote the sale, use or other dealings +in this Software without prior written authorization from The Open Group. + + +Copyright 1987 by Digital Equipment Corporation, Maynard, Massachusetts. + + All Rights Reserved + +Permission to use, copy, modify, and distribute this software and its +documentation for any purpose and without fee is hereby granted, +provided that the above copyright notice appear in all copies and that +both that copyright notice and this permission notice appear in +supporting documentation, and that the name of Digital not be +used in advertising or publicity pertaining to distribution of the +software without specific, written prior permission. + +DIGITAL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING +ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL +DIGITAL BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR +ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, +WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, +ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS +SOFTWARE. + +******************************************************************/ + + + +#ifdef HAVE_DIX_CONFIG_H +#include <dix-config.h> +#endif + +#include <X11/X.h> +#include <X11/Xmd.h> +#include "servermd.h" +#include "scrnintstr.h" +#include "dixstruct.h" +#include "cursorstr.h" +#include "dixfontstr.h" +#include "opaque.h" +#include "inputstr.h" +#include "xace.h" + +typedef struct _GlyphShare { + FontPtr font; + unsigned short sourceChar; + unsigned short maskChar; + CursorBitsPtr bits; + struct _GlyphShare *next; +} GlyphShare, *GlyphSharePtr; + +static GlyphSharePtr sharedGlyphs = (GlyphSharePtr)NULL; + +DevPrivateKeyRec cursorScreenDevPriv[MAXSCREENS]; + +#ifdef XFIXES +static CARD32 cursorSerial; +#endif + +static void +FreeCursorBits(CursorBitsPtr bits) +{ + if (--bits->refcnt > 0) + return; + free(bits->source); + free(bits->mask); +#ifdef ARGB_CURSOR + free(bits->argb); +#endif + dixFiniPrivates(bits, PRIVATE_CURSOR_BITS); + if (bits->refcnt == 0) + { + GlyphSharePtr *prev, this; + + for (prev = &sharedGlyphs; + (this = *prev) && (this->bits != bits); + prev = &this->next) + ; + if (this) + { + *prev = this->next; + CloseFont(this->font, (Font)0); + free(this); + } + free(bits); + } +} + +/** + * To be called indirectly by DeleteResource; must use exactly two args. + * + * \param value must conform to DeleteType + */ +int +FreeCursor(pointer value, XID cid) +{ + int nscr; + CursorPtr pCurs = (CursorPtr)value; + + ScreenPtr pscr; + DeviceIntPtr pDev = NULL; /* unused anyway */ + + if ( --pCurs->refcnt != 0) + return Success; + + for (nscr = 0; nscr < screenInfo.numScreens; nscr++) + { + pscr = screenInfo.screens[nscr]; + (void)( *pscr->UnrealizeCursor)(pDev, pscr, pCurs); + } + FreeCursorBits(pCurs->bits); + dixFiniPrivates(pCurs, PRIVATE_CURSOR); + free( pCurs); + return Success; +} + + +/* + * We check for empty cursors so that we won't have to display them + */ +static void +CheckForEmptyMask(CursorBitsPtr bits) +{ + unsigned char *msk = bits->mask; + int n = BitmapBytePad(bits->width) * bits->height; + + bits->emptyMask = FALSE; + while(n--) + if(*(msk++) != 0) return; +#ifdef ARGB_CURSOR + if (bits->argb) + { + CARD32 *argb = bits->argb; + int n = bits->width * bits->height; + while (n--) + if (*argb++ & 0xff000000) return; + } +#endif + bits->emptyMask = TRUE; +} + +/** + * realize the cursor for every screen. Do not change the refcnt, this will be + * changed when ChangeToCursor actually changes the sprite. + * + * @return Success if all cursors realize on all screens, BadAlloc if realize + * failed for a device on a given screen. + */ +static int +RealizeCursorAllScreens(CursorPtr pCurs) +{ + DeviceIntPtr pDev; + ScreenPtr pscr; + int nscr; + + for (nscr = 0; nscr < screenInfo.numScreens; nscr++) + { + pscr = screenInfo.screens[nscr]; + for (pDev = inputInfo.devices; pDev; pDev = pDev->next) + { + if (DevHasCursor(pDev)) + { + if (!( *pscr->RealizeCursor)(pDev, pscr, pCurs)) + { + /* Realize failed for device pDev on screen pscr. + * We have to assume that for all devices before, realize + * worked. We need to rollback all devices so far on the + * current screen and then all devices on previous + * screens. + */ + DeviceIntPtr pDevIt = inputInfo.devices; /*dev iterator*/ + while(pDevIt && pDevIt != pDev) + { + if (DevHasCursor(pDevIt)) + ( *pscr->UnrealizeCursor)(pDevIt, pscr, pCurs); + pDevIt = pDevIt->next; + } + while (--nscr >= 0) + { + pscr = screenInfo.screens[nscr]; + /* now unrealize all devices on previous screens */ + pDevIt = inputInfo.devices; + while (pDevIt) + { + if (DevHasCursor(pDevIt)) + ( *pscr->UnrealizeCursor)(pDevIt, pscr, pCurs); + pDevIt = pDevIt->next; + } + ( *pscr->UnrealizeCursor)(pDev, pscr, pCurs); + } + return BadAlloc; + } + } + } + } + + return Success; +} + + +/** + * does nothing about the resource table, just creates the data structure. + * does not copy the src and mask bits + * + * \param psrcbits server-defined padding + * \param pmaskbits server-defined padding + * \param argb no padding + */ +int +AllocARGBCursor(unsigned char *psrcbits, unsigned char *pmaskbits, + CARD32 *argb, CursorMetricPtr cm, + unsigned foreRed, unsigned foreGreen, unsigned foreBlue, + unsigned backRed, unsigned backGreen, unsigned backBlue, + CursorPtr *ppCurs, ClientPtr client, XID cid) +{ + CursorBitsPtr bits; + CursorPtr pCurs; + int rc; + + *ppCurs = NULL; + pCurs = (CursorPtr)calloc(CURSOR_REC_SIZE + CURSOR_BITS_SIZE, 1); + if (!pCurs) + return BadAlloc; + + bits = (CursorBitsPtr)((char *)pCurs + CURSOR_REC_SIZE); + dixInitPrivates(pCurs, pCurs + 1, PRIVATE_CURSOR); + dixInitPrivates(bits, bits + 1, PRIVATE_CURSOR_BITS) + bits->source = psrcbits; + bits->mask = pmaskbits; +#ifdef ARGB_CURSOR + bits->argb = argb; +#endif + bits->width = cm->width; + bits->height = cm->height; + bits->xhot = cm->xhot; + bits->yhot = cm->yhot; + pCurs->refcnt = 1; + bits->refcnt = -1; + CheckForEmptyMask(bits); + pCurs->bits = bits; +#ifdef XFIXES + pCurs->serialNumber = ++cursorSerial; + pCurs->name = None; +#endif + + pCurs->foreRed = foreRed; + pCurs->foreGreen = foreGreen; + pCurs->foreBlue = foreBlue; + + pCurs->backRed = backRed; + pCurs->backGreen = backGreen; + pCurs->backBlue = backBlue; + + pCurs->id = cid; + + /* security creation/labeling check */ + rc = XaceHook(XACE_RESOURCE_ACCESS, client, cid, RT_CURSOR, + pCurs, RT_NONE, NULL, DixCreateAccess); + if (rc != Success) + goto error; + + rc = RealizeCursorAllScreens(pCurs); + if (rc != Success) + goto error; + + *ppCurs = pCurs; + return Success; + +error: + FreeCursorBits(bits); + dixFiniPrivates(pCurs, PRIVATE_CURSOR); + free(pCurs); + + return rc; +} + +int +AllocGlyphCursor(Font source, unsigned sourceChar, Font mask, unsigned maskChar, + unsigned foreRed, unsigned foreGreen, unsigned foreBlue, + unsigned backRed, unsigned backGreen, unsigned backBlue, + CursorPtr *ppCurs, ClientPtr client, XID cid) +{ + FontPtr sourcefont, maskfont; + unsigned char *srcbits; + unsigned char *mskbits; + CursorMetricRec cm; + int rc; + CursorBitsPtr bits; + CursorPtr pCurs; + GlyphSharePtr pShare; + + rc = dixLookupResourceByType((pointer *)&sourcefont, source, RT_FONT, client, + DixUseAccess); + if (rc != Success) + { + client->errorValue = source; + return rc; + } + rc = dixLookupResourceByType((pointer *)&maskfont, mask, RT_FONT, client, + DixUseAccess); + if (rc != Success && mask != None) + { + client->errorValue = mask; + return rc; + } + if (sourcefont != maskfont) + pShare = (GlyphSharePtr)NULL; + else + { + for (pShare = sharedGlyphs; + pShare && + ((pShare->font != sourcefont) || + (pShare->sourceChar != sourceChar) || + (pShare->maskChar != maskChar)); + pShare = pShare->next) + ; + } + if (pShare) + { + pCurs = (CursorPtr)calloc(CURSOR_REC_SIZE, 1); + if (!pCurs) + return BadAlloc; + dixInitPrivates(pCurs, pCurs + 1, PRIVATE_CURSOR); + bits = pShare->bits; + bits->refcnt++; + } + else + { + if (!CursorMetricsFromGlyph(sourcefont, sourceChar, &cm)) + { + client->errorValue = sourceChar; + return BadValue; + } + if (!maskfont) + { + long n; + unsigned char *mskptr; + + n = BitmapBytePad(cm.width)*(long)cm.height; + mskptr = mskbits = malloc(n); + if (!mskptr) + return BadAlloc; + while (--n >= 0) + *mskptr++ = ~0; + } + else + { + if (!CursorMetricsFromGlyph(maskfont, maskChar, &cm)) + { + client->errorValue = maskChar; + return BadValue; + } + if ((rc = ServerBitsFromGlyph(maskfont, maskChar, &cm, &mskbits))) + return rc; + } + if ((rc = ServerBitsFromGlyph(sourcefont, sourceChar, &cm, &srcbits))) + { + free(mskbits); + return rc; + } + if (sourcefont != maskfont) + { + pCurs = + (CursorPtr)calloc(CURSOR_REC_SIZE + CURSOR_BITS_SIZE, 1); + if (pCurs) + bits = (CursorBitsPtr)((char *)pCurs + CURSOR_REC_SIZE); + else + bits = (CursorBitsPtr)NULL; + } + else + { + pCurs = (CursorPtr)calloc(CURSOR_REC_SIZE, 1); + if (pCurs) + bits = (CursorBitsPtr)calloc(CURSOR_BITS_SIZE, 1); + else + bits = (CursorBitsPtr)NULL; + } + if (!bits) + { + free(pCurs); + free(mskbits); + free(srcbits); + return BadAlloc; + } + dixInitPrivates(pCurs, pCurs + 1, PRIVATE_CURSOR); + dixInitPrivates(bits, bits + 1, PRIVATE_CURSOR_BITS); + bits->source = srcbits; + bits->mask = mskbits; +#ifdef ARGB_CURSOR + bits->argb = 0; +#endif + bits->width = cm.width; + bits->height = cm.height; + bits->xhot = cm.xhot; + bits->yhot = cm.yhot; + if (sourcefont != maskfont) + bits->refcnt = -1; + else + { + bits->refcnt = 1; + pShare = malloc(sizeof(GlyphShare)); + if (!pShare) + { + FreeCursorBits(bits); + return BadAlloc; + } + pShare->font = sourcefont; + sourcefont->refcnt++; + pShare->sourceChar = sourceChar; + pShare->maskChar = maskChar; + pShare->bits = bits; + pShare->next = sharedGlyphs; + sharedGlyphs = pShare; + } + } + + CheckForEmptyMask(bits); + pCurs->bits = bits; + pCurs->refcnt = 1; +#ifdef XFIXES + pCurs->serialNumber = ++cursorSerial; + pCurs->name = None; +#endif + + pCurs->foreRed = foreRed; + pCurs->foreGreen = foreGreen; + pCurs->foreBlue = foreBlue; + + pCurs->backRed = backRed; + pCurs->backGreen = backGreen; + pCurs->backBlue = backBlue; + + pCurs->id = cid; + + /* security creation/labeling check */ + rc = XaceHook(XACE_RESOURCE_ACCESS, client, cid, RT_CURSOR, + pCurs, RT_NONE, NULL, DixCreateAccess); + if (rc != Success) + goto error; + + rc = RealizeCursorAllScreens(pCurs); + if (rc != Success) + goto error; + + *ppCurs = pCurs; + return Success; + +error: + FreeCursorBits(bits); + dixFiniPrivates(pCurs, PRIVATE_CURSOR); + free(pCurs); + + return rc; +} + +/** CreateRootCursor + * + * look up the name of a font + * open the font + * add the font to the resource table + * make a cursor from the glyphs + * add the cursor to the resource table + *************************************************************/ + +CursorPtr +CreateRootCursor(char *unused1, unsigned int unused2) +{ + CursorPtr curs; + FontPtr cursorfont; + int err; + XID fontID; + + fontID = FakeClientID(0); + err = OpenFont(serverClient, fontID, FontLoadAll | FontOpenSync, + (unsigned)strlen(defaultCursorFont), defaultCursorFont); + if (err != Success) + return NullCursor; + + err = dixLookupResourceByType((pointer *)&cursorfont, fontID, RT_FONT, + serverClient, DixReadAccess); + if (err != Success) + return NullCursor; + if (AllocGlyphCursor(fontID, 0, fontID, 1, 0, 0, 0, ~0, ~0, ~0, + &curs, serverClient, (XID)0) != Success) + return NullCursor; + + if (!AddResource(FakeClientID(0), RT_CURSOR, (pointer)curs)) + return NullCursor; + + return curs; +} diff --git a/xorg-server/dix/dispatch.c b/xorg-server/dix/dispatch.c index 601b14a71..192c8c34e 100644 --- a/xorg-server/dix/dispatch.c +++ b/xorg-server/dix/dispatch.c @@ -2976,11 +2976,17 @@ ProcCreateCursor (ClientPtr client) &pCursor, client, stuff->cid); if (rc != Success) - return rc; - if (!AddResource(stuff->cid, RT_CURSOR, (pointer)pCursor)) - return BadAlloc; + goto bail; + if (!AddResource(stuff->cid, RT_CURSOR, (pointer)pCursor)) { + rc = BadAlloc; + goto bail; + } return Success; +bail: + free(srcbits); + free(mskbits); + return rc; } int diff --git a/xorg-server/hw/xfree86/common/xf86xv.c b/xorg-server/hw/xfree86/common/xf86xv.c index 8115075b3..b46dfefed 100644 --- a/xorg-server/hw/xfree86/common/xf86xv.c +++ b/xorg-server/hw/xfree86/common/xf86xv.c @@ -1,2183 +1,2190 @@ -/*
- * XFree86 Xv DDX written by Mark Vojkovich (markv@valinux.com)
- */
-/*
- * Copyright (c) 1998-2003 by The XFree86 Project, Inc.
- *
- * Permission is hereby granted, free of charge, to any person obtaining a
- * copy of this software and associated documentation files (the "Software"),
- * to deal in the Software without restriction, including without limitation
- * the rights to use, copy, modify, merge, publish, distribute, sublicense,
- * and/or sell copies of the Software, and to permit persons to whom the
- * Software is furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
- * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) 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.
- *
- * Except as contained in this notice, the name of the copyright holder(s)
- * and author(s) shall not be used in advertising or otherwise to promote
- * the sale, use or other dealings in this Software without prior written
- * authorization from the copyright holder(s) and author(s).
- */
-
-
-#ifdef HAVE_XORG_CONFIG_H
-#include <xorg-config.h>
-#endif
-
-#include "misc.h"
-#include "xf86.h"
-#include "xf86_OSproc.h"
-
-#include <X11/X.h>
-#include <X11/Xproto.h>
-#include "scrnintstr.h"
-#include "regionstr.h"
-#include "windowstr.h"
-#include "pixmapstr.h"
-#include "mivalidate.h"
-#include "validate.h"
-#include "resource.h"
-#include "gcstruct.h"
-#include "dixstruct.h"
-
-#include <X11/extensions/Xv.h>
-#include <X11/extensions/Xvproto.h>
-#include "xvdix.h"
-#include "xvmodproc.h"
-
-#include "xf86xvpriv.h"
-
-
-/* XvScreenRec fields */
-
-static Bool xf86XVCloseScreen(int, ScreenPtr);
-static int xf86XVQueryAdaptors(ScreenPtr, XvAdaptorPtr *, int *);
-
-/* XvAdaptorRec fields */
-
-static int xf86XVAllocatePort(unsigned long, XvPortPtr, XvPortPtr*);
-static int xf86XVFreePort(XvPortPtr);
-static int xf86XVPutVideo(ClientPtr, DrawablePtr,XvPortPtr, GCPtr,
- INT16, INT16, CARD16, CARD16,
- INT16, INT16, CARD16, CARD16);
-static int xf86XVPutStill(ClientPtr, DrawablePtr,XvPortPtr, GCPtr,
- INT16, INT16, CARD16, CARD16,
- INT16, INT16, CARD16, CARD16);
-static int xf86XVGetVideo(ClientPtr, DrawablePtr,XvPortPtr, GCPtr,
- INT16, INT16, CARD16, CARD16,
- INT16, INT16, CARD16, CARD16);
-static int xf86XVGetStill(ClientPtr, DrawablePtr,XvPortPtr, GCPtr,
- INT16, INT16, CARD16, CARD16,
- INT16, INT16, CARD16, CARD16);
-static int xf86XVStopVideo(ClientPtr, XvPortPtr, DrawablePtr);
-static int xf86XVSetPortAttribute(ClientPtr, XvPortPtr, Atom, INT32);
-static int xf86XVGetPortAttribute(ClientPtr, XvPortPtr, Atom, INT32*);
-static int xf86XVQueryBestSize(ClientPtr, XvPortPtr, CARD8,
- CARD16, CARD16,CARD16, CARD16,
- unsigned int*, unsigned int*);
-static int xf86XVPutImage(ClientPtr, DrawablePtr, XvPortPtr, GCPtr,
- INT16, INT16, CARD16, CARD16,
- INT16, INT16, CARD16, CARD16,
- XvImagePtr, unsigned char*, Bool,
- CARD16, CARD16);
-static int xf86XVQueryImageAttributes(ClientPtr, XvPortPtr, XvImagePtr,
- CARD16*, CARD16*, int*, int*);
-
-
-/* ScreenRec fields */
-
-static Bool xf86XVDestroyWindow(WindowPtr pWin);
-static void xf86XVWindowExposures(WindowPtr pWin, RegionPtr r1, RegionPtr r2);
-static void xf86XVPostValidateTree(WindowPtr pWin, WindowPtr pLayerWin, VTKind kind);
-static void xf86XVClipNotify(WindowPtr pWin, int dx, int dy);
-
-#define PostValidateTreeUndefined ((PostValidateTreeProcPtr)-1)
-
-/* ScrnInfoRec functions */
-
-static Bool xf86XVEnterVT(int, int);
-static void xf86XVLeaveVT(int, int);
-static void xf86XVAdjustFrame(int index, int x, int y, int flags);
-static void xf86XVModeSet(ScrnInfoPtr pScrn);
-
-/* misc */
-
-static Bool xf86XVInitAdaptors(ScreenPtr, XF86VideoAdaptorPtr*, int);
-
-
-static DevPrivateKeyRec XF86XVWindowKeyRec;
-#define XF86XVWindowKey (&XF86XVWindowKeyRec)
-
-DevPrivateKey XF86XvScreenKey;
-
-static unsigned long PortResource = 0;
-
-DevPrivateKey (*XvGetScreenKeyProc)(void) = NULL;
-unsigned long (*XvGetRTPortProc)(void) = NULL;
-int (*XvScreenInitProc)(ScreenPtr) = NULL;
-
-#define GET_XV_SCREEN(pScreen) \
- ((XvScreenPtr)dixLookupPrivate(&(pScreen)->devPrivates, XF86XvScreenKey))
-
-#define GET_XF86XV_SCREEN(pScreen) \
- ((XF86XVScreenPtr)(GET_XV_SCREEN(pScreen)->devPriv.ptr))
-
-#define GET_XF86XV_WINDOW(pWin) \
- ((XF86XVWindowPtr)dixLookupPrivate(&(pWin)->devPrivates, XF86XVWindowKey))
-
-static xf86XVInitGenericAdaptorPtr *GenDrivers = NULL;
-static int NumGenDrivers = 0;
-
-int
-xf86XVRegisterGenericAdaptorDriver(
- xf86XVInitGenericAdaptorPtr InitFunc
-){
- xf86XVInitGenericAdaptorPtr *newdrivers;
-
- newdrivers = realloc(GenDrivers, sizeof(xf86XVInitGenericAdaptorPtr) *
- (1 + NumGenDrivers));
- if (!newdrivers)
- return 0;
- GenDrivers = newdrivers;
-
- GenDrivers[NumGenDrivers++] = InitFunc;
-
- return 1;
-}
-
-int
-xf86XVListGenericAdaptors(
- ScrnInfoPtr pScrn,
- XF86VideoAdaptorPtr **adaptors
-){
- int i,j,n,num;
- XF86VideoAdaptorPtr *DrivAdap,*new;
-
- num = 0;
- *adaptors = NULL;
- /*
- * The v4l driver registers itself first, but can use surfaces registered
- * by other drivers. So, call the v4l driver last.
- */
- for (i = NumGenDrivers; --i >= 0; ) {
- DrivAdap = NULL;
- n = (*GenDrivers[i])(pScrn, &DrivAdap);
- if (0 == n)
- continue;
- new = realloc(*adaptors, sizeof(XF86VideoAdaptorPtr) * (num+n));
- if (NULL == new)
- continue;
- *adaptors = new;
- for (j = 0; j < n; j++, num++)
- (*adaptors)[num] = DrivAdap[j];
- }
- return num;
-}
-
-
-/**************** Offscreen surface stuff *******************/
-
-typedef struct {
- XF86OffscreenImagePtr images;
- int num;
-} OffscreenImageRec;
-
-static DevPrivateKeyRec OffscreenPrivateKeyRec;
-#define OffscreenPrivateKey (&OffscreenPrivateKeyRec)
-#define GetOffscreenImage(pScreen) ((OffscreenImageRec *) dixLookupPrivate(&(pScreen)->devPrivates, OffscreenPrivateKey))
-
-Bool
-xf86XVRegisterOffscreenImages(
- ScreenPtr pScreen,
- XF86OffscreenImagePtr images,
- int num
-){
- OffscreenImageRec *OffscreenImage;
- /* This function may be called before xf86XVScreenInit, so there's
- * no better place than this to call dixRegisterPrivateKey to ensure we
- * have space reserved. After the first call it is a no-op. */
- if(!dixRegisterPrivateKey(OffscreenPrivateKey, PRIVATE_SCREEN, sizeof(OffscreenImageRec)) ||
- !(OffscreenImage = GetOffscreenImage(pScreen)))
- /* Every X.org driver assumes this function always succeeds, so
- * just die on allocation failure. */
- FatalError("Could not allocate private storage for XV offscreen images.\n");
-
- OffscreenImage->num = num;
- OffscreenImage->images = images;
- return TRUE;
-}
-
-XF86OffscreenImagePtr
-xf86XVQueryOffscreenImages(
- ScreenPtr pScreen,
- int *num
-){
- OffscreenImageRec *OffscreenImage = GetOffscreenImage(pScreen);
- *num = OffscreenImage->num;
- return OffscreenImage->images;
-}
-
-
-XF86VideoAdaptorPtr
-xf86XVAllocateVideoAdaptorRec(ScrnInfoPtr pScrn)
-{
- return calloc(1, sizeof(XF86VideoAdaptorRec));
-}
-
-void
-xf86XVFreeVideoAdaptorRec(XF86VideoAdaptorPtr ptr)
-{
- free(ptr);
-}
-
-
-Bool
-xf86XVScreenInit(
- ScreenPtr pScreen,
- XF86VideoAdaptorPtr *adaptors,
- int num
-){
- ScrnInfoPtr pScrn;
- XF86XVScreenPtr ScreenPriv;
- XvScreenPtr pxvs;
-
- if(num <= 0 ||
- !XvGetScreenKeyProc || !XvGetRTPortProc || !XvScreenInitProc)
- return FALSE;
-
- if(Success != (*XvScreenInitProc)(pScreen)) return FALSE;
-
- if (!dixRegisterPrivateKey(&XF86XVWindowKeyRec, PRIVATE_WINDOW, 0))
- return FALSE;
-
- XF86XvScreenKey = (*XvGetScreenKeyProc)();
-
- PortResource = (*XvGetRTPortProc)();
-
- pxvs = GET_XV_SCREEN(pScreen);
-
- /* Anyone initializing the Xv layer must provide these two.
- The Xv di layer calls them without even checking if they exist! */
-
- pxvs->ddCloseScreen = xf86XVCloseScreen;
- pxvs->ddQueryAdaptors = xf86XVQueryAdaptors;
-
- /* The Xv di layer provides us with a private hook so that we don't
- have to allocate our own screen private. They also provide
- a CloseScreen hook so that we don't have to wrap it. I'm not
- sure that I appreciate that. */
-
- ScreenPriv = malloc(sizeof(XF86XVScreenRec));
- pxvs->devPriv.ptr = (pointer)ScreenPriv;
-
- if(!ScreenPriv) return FALSE;
-
- pScrn = xf86Screens[pScreen->myNum];
-
- ScreenPriv->DestroyWindow = pScreen->DestroyWindow;
- ScreenPriv->WindowExposures = pScreen->WindowExposures;
- ScreenPriv->PostValidateTree = PostValidateTreeUndefined;
- ScreenPriv->ClipNotify = pScreen->ClipNotify;
- ScreenPriv->EnterVT = pScrn->EnterVT;
- ScreenPriv->LeaveVT = pScrn->LeaveVT;
- ScreenPriv->AdjustFrame = pScrn->AdjustFrame;
- ScreenPriv->ModeSet = pScrn->ModeSet;
-
- pScreen->DestroyWindow = xf86XVDestroyWindow;
- pScreen->WindowExposures = xf86XVWindowExposures;
- pScreen->ClipNotify = xf86XVClipNotify;
- pScrn->EnterVT = xf86XVEnterVT;
- pScrn->LeaveVT = xf86XVLeaveVT;
- if(pScrn->AdjustFrame)
- pScrn->AdjustFrame = xf86XVAdjustFrame;
- pScrn->ModeSet = xf86XVModeSet;
-
- if(!xf86XVInitAdaptors(pScreen, adaptors, num))
- return FALSE;
-
- return TRUE;
-}
-
-static void
-xf86XVFreeAdaptor(XvAdaptorPtr pAdaptor)
-{
- int i;
-
- free(pAdaptor->name);
-
- if(pAdaptor->pEncodings) {
- XvEncodingPtr pEncode = pAdaptor->pEncodings;
-
- for(i = 0; i < pAdaptor->nEncodings; i++, pEncode++)
- free(pEncode->name);
- free(pAdaptor->pEncodings);
- }
-
- free(pAdaptor->pFormats);
-
- if(pAdaptor->pPorts) {
- XvPortPtr pPort = pAdaptor->pPorts;
- XvPortRecPrivatePtr pPriv;
-
- for(i = 0; i < pAdaptor->nPorts; i++, pPort++) {
- pPriv = (XvPortRecPrivatePtr)pPort->devPriv.ptr;
- if(pPriv) {
- if(pPriv->clientClip)
- RegionDestroy(pPriv->clientClip);
- if(pPriv->pCompositeClip && pPriv->FreeCompositeClip)
- RegionDestroy(pPriv->pCompositeClip);
- if (pPriv->ckeyFilled)
- RegionDestroy(pPriv->ckeyFilled);
- free(pPriv);
- }
- }
- free(pAdaptor->pPorts);
- }
-
- if(pAdaptor->nAttributes) {
- XvAttributePtr pAttribute = pAdaptor->pAttributes;
-
- for(i = 0; i < pAdaptor->nAttributes; i++, pAttribute++)
- free(pAttribute->name);
- free(pAdaptor->pAttributes);
- }
-
- free(pAdaptor->pImages);
- free(pAdaptor->devPriv.ptr);
-}
-
-static Bool
-xf86XVInitAdaptors(
- ScreenPtr pScreen,
- XF86VideoAdaptorPtr *infoPtr,
- int number
-) {
- XvScreenPtr pxvs = GET_XV_SCREEN(pScreen);
- ScrnInfoPtr pScrn = xf86Screens[pScreen->myNum];
- XF86VideoAdaptorPtr adaptorPtr;
- XvAdaptorPtr pAdaptor, pa;
- XvAdaptorRecPrivatePtr adaptorPriv;
- int na, numAdaptor;
- XvPortRecPrivatePtr portPriv;
- XvPortPtr pPort, pp;
- int numPort;
- XF86AttributePtr attributePtr;
- XvAttributePtr pAttribute, pat;
- XF86VideoFormatPtr formatPtr;
- XvFormatPtr pFormat, pf;
- int numFormat, totFormat;
- XF86VideoEncodingPtr encodingPtr;
- XvEncodingPtr pEncode, pe;
- XF86ImagePtr imagePtr;
- XvImagePtr pImage, pi;
- int numVisuals;
- VisualPtr pVisual;
- int i;
-
- pxvs->nAdaptors = 0;
- pxvs->pAdaptors = NULL;
-
- if(!(pAdaptor = calloc(number, sizeof(XvAdaptorRec))))
- return FALSE;
-
- for(pa = pAdaptor, na = 0, numAdaptor = 0; na < number; na++, adaptorPtr++) {
- adaptorPtr = infoPtr[na];
-
- if(!adaptorPtr->StopVideo || !adaptorPtr->SetPortAttribute ||
- !adaptorPtr->GetPortAttribute || !adaptorPtr->QueryBestSize)
- continue;
-
- /* client libs expect at least one encoding */
- if(!adaptorPtr->nEncodings || !adaptorPtr->pEncodings)
- continue;
-
- pa->type = adaptorPtr->type;
-
- if(!adaptorPtr->PutVideo && !adaptorPtr->GetVideo)
- pa->type &= ~XvVideoMask;
-
- if(!adaptorPtr->PutStill && !adaptorPtr->GetStill)
- pa->type &= ~XvStillMask;
-
- if(!adaptorPtr->PutImage || !adaptorPtr->QueryImageAttributes)
- pa->type &= ~XvImageMask;
-
- if(!adaptorPtr->PutVideo && !adaptorPtr->PutImage &&
- !adaptorPtr->PutStill)
- pa->type &= ~XvInputMask;
-
- if(!adaptorPtr->GetVideo && !adaptorPtr->GetStill)
- pa->type &= ~XvOutputMask;
-
- if(!(adaptorPtr->type & (XvPixmapMask | XvWindowMask)))
- continue;
- if(!(adaptorPtr->type & (XvImageMask | XvVideoMask | XvStillMask)))
- continue;
-
- pa->pScreen = pScreen;
- pa->ddAllocatePort = xf86XVAllocatePort;
- pa->ddFreePort = xf86XVFreePort;
- pa->ddPutVideo = xf86XVPutVideo;
- pa->ddPutStill = xf86XVPutStill;
- pa->ddGetVideo = xf86XVGetVideo;
- pa->ddGetStill = xf86XVGetStill;
- pa->ddStopVideo = xf86XVStopVideo;
- pa->ddPutImage = xf86XVPutImage;
- pa->ddSetPortAttribute = xf86XVSetPortAttribute;
- pa->ddGetPortAttribute = xf86XVGetPortAttribute;
- pa->ddQueryBestSize = xf86XVQueryBestSize;
- pa->ddQueryImageAttributes = xf86XVQueryImageAttributes;
- pa->name = strdup(adaptorPtr->name);
-
- if(adaptorPtr->nEncodings &&
- (pEncode = calloc(adaptorPtr->nEncodings, sizeof(XvEncodingRec)))) {
-
- for(pe = pEncode, encodingPtr = adaptorPtr->pEncodings, i = 0;
- i < adaptorPtr->nEncodings; pe++, i++, encodingPtr++)
- {
- pe->id = encodingPtr->id;
- pe->pScreen = pScreen;
- pe->name = strdup(encodingPtr->name);
- pe->width = encodingPtr->width;
- pe->height = encodingPtr->height;
- pe->rate.numerator = encodingPtr->rate.numerator;
- pe->rate.denominator = encodingPtr->rate.denominator;
- }
- pa->nEncodings = adaptorPtr->nEncodings;
- pa->pEncodings = pEncode;
- }
-
- if(adaptorPtr->nImages &&
- (pImage = calloc(adaptorPtr->nImages, sizeof(XvImageRec)))) {
-
- for(i = 0, pi = pImage, imagePtr = adaptorPtr->pImages;
- i < adaptorPtr->nImages; i++, pi++, imagePtr++)
- {
- pi->id = imagePtr->id;
- pi->type = imagePtr->type;
- pi->byte_order = imagePtr->byte_order;
- memcpy(pi->guid, imagePtr->guid, 16);
- pi->bits_per_pixel = imagePtr->bits_per_pixel;
- pi->format = imagePtr->format;
- pi->num_planes = imagePtr->num_planes;
- pi->depth = imagePtr->depth;
- pi->red_mask = imagePtr->red_mask;
- pi->green_mask = imagePtr->green_mask;
- pi->blue_mask = imagePtr->blue_mask;
- pi->y_sample_bits = imagePtr->y_sample_bits;
- pi->u_sample_bits = imagePtr->u_sample_bits;
- pi->v_sample_bits = imagePtr->v_sample_bits;
- pi->horz_y_period = imagePtr->horz_y_period;
- pi->horz_u_period = imagePtr->horz_u_period;
- pi->horz_v_period = imagePtr->horz_v_period;
- pi->vert_y_period = imagePtr->vert_y_period;
- pi->vert_u_period = imagePtr->vert_u_period;
- pi->vert_v_period = imagePtr->vert_v_period;
- memcpy(pi->component_order, imagePtr->component_order, 32);
- pi->scanline_order = imagePtr->scanline_order;
- }
- pa->nImages = adaptorPtr->nImages;
- pa->pImages = pImage;
- }
-
- if(adaptorPtr->nAttributes &&
- (pAttribute = calloc(adaptorPtr->nAttributes, sizeof(XvAttributeRec))))
- {
- for(pat = pAttribute, attributePtr = adaptorPtr->pAttributes, i = 0;
- i < adaptorPtr->nAttributes; pat++, i++, attributePtr++)
- {
- pat->flags = attributePtr->flags;
- pat->min_value = attributePtr->min_value;
- pat->max_value = attributePtr->max_value;
- pat->name = strdup(attributePtr->name);
- }
- pa->nAttributes = adaptorPtr->nAttributes;
- pa->pAttributes = pAttribute;
- }
-
-
- totFormat = adaptorPtr->nFormats;
-
- if(!(pFormat = calloc(totFormat, sizeof(XvFormatRec)))) {
- xf86XVFreeAdaptor(pa);
- continue;
- }
- for(pf = pFormat, i = 0, numFormat = 0, formatPtr = adaptorPtr->pFormats;
- i < adaptorPtr->nFormats; i++, formatPtr++)
- {
- numVisuals = pScreen->numVisuals;
- pVisual = pScreen->visuals;
-
- while(numVisuals--) {
- if((pVisual->class == formatPtr->class) &&
- (pVisual->nplanes == formatPtr->depth)) {
-
- if(numFormat >= totFormat) {
- void *moreSpace;
- totFormat *= 2;
- moreSpace = realloc(pFormat,
- totFormat * sizeof(XvFormatRec));
- if(!moreSpace) break;
- pFormat = moreSpace;
- pf = pFormat + numFormat;
- }
-
- pf->visual = pVisual->vid;
- pf->depth = formatPtr->depth;
-
- pf++;
- numFormat++;
- }
- pVisual++;
- }
- }
- pa->nFormats = numFormat;
- pa->pFormats = pFormat;
- if(!numFormat) {
- xf86XVFreeAdaptor(pa);
- continue;
- }
-
- if(!(adaptorPriv = calloc(1, sizeof(XvAdaptorRecPrivate)))) {
- xf86XVFreeAdaptor(pa);
- continue;
- }
-
- adaptorPriv->flags = adaptorPtr->flags;
- adaptorPriv->PutVideo = adaptorPtr->PutVideo;
- adaptorPriv->PutStill = adaptorPtr->PutStill;
- adaptorPriv->GetVideo = adaptorPtr->GetVideo;
- adaptorPriv->GetStill = adaptorPtr->GetStill;
- adaptorPriv->StopVideo = adaptorPtr->StopVideo;
- adaptorPriv->SetPortAttribute = adaptorPtr->SetPortAttribute;
- adaptorPriv->GetPortAttribute = adaptorPtr->GetPortAttribute;
- adaptorPriv->QueryBestSize = adaptorPtr->QueryBestSize;
- adaptorPriv->QueryImageAttributes = adaptorPtr->QueryImageAttributes;
- adaptorPriv->PutImage = adaptorPtr->PutImage;
- adaptorPriv->ReputImage = adaptorPtr->ReputImage; /* image/still */
-
- pa->devPriv.ptr = (pointer)adaptorPriv;
-
- if(!(pPort = calloc(adaptorPtr->nPorts, sizeof(XvPortRec)))) {
- xf86XVFreeAdaptor(pa);
- continue;
- }
- for(pp = pPort, i = 0, numPort = 0;
- i < adaptorPtr->nPorts; i++) {
-
- if(!(pp->id = FakeClientID(0)))
- continue;
-
- if(!(portPriv = calloc(1, sizeof(XvPortRecPrivate))))
- continue;
-
- if(!AddResource(pp->id, PortResource, pp)) {
- free(portPriv);
- continue;
- }
-
- pp->pAdaptor = pa;
- pp->pNotify = (XvPortNotifyPtr)NULL;
- pp->pDraw = (DrawablePtr)NULL;
- pp->client = (ClientPtr)NULL;
- pp->grab.client = (ClientPtr)NULL;
- pp->time = currentTime;
- pp->devPriv.ptr = portPriv;
-
- portPriv->pScrn = pScrn;
- portPriv->AdaptorRec = adaptorPriv;
- portPriv->DevPriv.ptr = adaptorPtr->pPortPrivates[i].ptr;
-
- pp++;
- numPort++;
- }
- pa->nPorts = numPort;
- pa->pPorts = pPort;
- if(!numPort) {
- xf86XVFreeAdaptor(pa);
- continue;
- }
-
- pa->base_id = pPort->id;
-
- pa++;
- numAdaptor++;
- }
-
- if(numAdaptor) {
- pxvs->nAdaptors = numAdaptor;
- pxvs->pAdaptors = pAdaptor;
- } else {
- free(pAdaptor);
- return FALSE;
- }
-
- return TRUE;
-}
-
-/* Video should be clipped to the intersection of the window cliplist
- and the client cliplist specified in the GC for which the video was
- initialized. When we need to reclip a window, the GC that started
- the video may not even be around anymore. That's why we save the
- client clip from the GC when the video is initialized. We then
- use xf86XVUpdateCompositeClip to calculate the new composite clip
- when we need it. This is different from what DEC did. They saved
- the GC and used it's clip list when they needed to reclip the window,
- even if the client clip was different from the one the video was
- initialized with. If the original GC was destroyed, they had to stop
- the video. I like the new method better (MArk).
-
- This function only works for windows. Will need to rewrite when
- (if) we support pixmap rendering.
-*/
-
-static void
-xf86XVUpdateCompositeClip(XvPortRecPrivatePtr portPriv)
-{
- RegionPtr pregWin, pCompositeClip;
- WindowPtr pWin;
- Bool freeCompClip = FALSE;
-
- if(portPriv->pCompositeClip)
- return;
-
- pWin = (WindowPtr)portPriv->pDraw;
-
- /* get window clip list */
- if(portPriv->subWindowMode == IncludeInferiors) {
- pregWin = NotClippedByChildren(pWin);
- freeCompClip = TRUE;
- } else
- pregWin = &pWin->clipList;
-
- if(!portPriv->clientClip) {
- portPriv->pCompositeClip = pregWin;
- portPriv->FreeCompositeClip = freeCompClip;
- return;
- }
-
- pCompositeClip = RegionCreate(NullBox, 1);
- RegionCopy(pCompositeClip, portPriv->clientClip);
- RegionTranslate(pCompositeClip,
- portPriv->pDraw->x, portPriv->pDraw->y);
- RegionIntersect(pCompositeClip, pregWin, pCompositeClip);
-
- portPriv->pCompositeClip = pCompositeClip;
- portPriv->FreeCompositeClip = TRUE;
-
- if(freeCompClip) {
- RegionDestroy(pregWin);
- }
-}
-
-/* Save the current clientClip and update the CompositeClip whenever
- we have a fresh GC */
-
-static void
-xf86XVCopyClip(
- XvPortRecPrivatePtr portPriv,
- GCPtr pGC
-){
- /* copy the new clip if it exists */
- if((pGC->clientClipType == CT_REGION) && pGC->clientClip) {
- if(!portPriv->clientClip)
- portPriv->clientClip = RegionCreate(NullBox, 1);
- /* Note: this is in window coordinates */
- RegionCopy(portPriv->clientClip, pGC->clientClip);
- RegionTranslate(portPriv->clientClip,
- pGC->clipOrg.x, pGC->clipOrg.y);
- } else if(portPriv->clientClip) { /* free the old clientClip */
- RegionDestroy(portPriv->clientClip);
- portPriv->clientClip = NULL;
- }
-
- /* get rid of the old clip list */
- if(portPriv->pCompositeClip && portPriv->FreeCompositeClip) {
- RegionDestroy(portPriv->pCompositeClip);
- }
-
- portPriv->pCompositeClip = pGC->pCompositeClip;
- portPriv->FreeCompositeClip = FALSE;
- portPriv->subWindowMode = pGC->subWindowMode;
-}
-
-static void
-xf86XVCopyCompositeClip(XvPortRecPrivatePtr portPriv,
- GCPtr pGC,
- DrawablePtr pDraw)
-{
- if (!portPriv->clientClip)
- portPriv->clientClip = RegionCreate(NullBox, 1);
- /* Keep the original GC composite clip around for ReputImage */
- RegionCopy(portPriv->clientClip, pGC->pCompositeClip);
- RegionTranslate(portPriv->clientClip,
- -pDraw->x, -pDraw->y);
-
- /* get rid of the old clip list */
- if (portPriv->pCompositeClip && portPriv->FreeCompositeClip)
- RegionDestroy(portPriv->pCompositeClip);
-
- portPriv->pCompositeClip = pGC->pCompositeClip;
- portPriv->FreeCompositeClip = FALSE;
- portPriv->subWindowMode = pGC->subWindowMode;
-}
-
-static int
-xf86XVRegetVideo(XvPortRecPrivatePtr portPriv)
-{
- RegionRec WinRegion;
- RegionRec ClipRegion;
- BoxRec WinBox;
- int ret = Success;
- Bool clippedAway = FALSE;
-
- xf86XVUpdateCompositeClip(portPriv);
-
- /* translate the video region to the screen */
- WinBox.x1 = portPriv->pDraw->x + portPriv->drw_x;
- WinBox.y1 = portPriv->pDraw->y + portPriv->drw_y;
- WinBox.x2 = WinBox.x1 + portPriv->drw_w;
- WinBox.y2 = WinBox.y1 + portPriv->drw_h;
-
- /* clip to the window composite clip */
- RegionInit(&WinRegion, &WinBox, 1);
- RegionNull(&ClipRegion);
- RegionIntersect(&ClipRegion, &WinRegion, portPriv->pCompositeClip);
-
- /* that's all if it's totally obscured */
- if(!RegionNotEmpty(&ClipRegion)) {
- clippedAway = TRUE;
- goto CLIP_VIDEO_BAILOUT;
- }
-
- if(portPriv->AdaptorRec->flags & VIDEO_INVERT_CLIPLIST) {
- RegionSubtract(&ClipRegion, &WinRegion, &ClipRegion);
- }
-
- ret = (*portPriv->AdaptorRec->GetVideo)(portPriv->pScrn,
- portPriv->vid_x, portPriv->vid_y,
- WinBox.x1, WinBox.y1,
- portPriv->vid_w, portPriv->vid_h,
- portPriv->drw_w, portPriv->drw_h,
- &ClipRegion, portPriv->DevPriv.ptr,
- portPriv->pDraw);
-
- if(ret == Success)
- portPriv->isOn = XV_ON;
-
-CLIP_VIDEO_BAILOUT:
-
- if((clippedAway || (ret != Success)) && portPriv->isOn == XV_ON) {
- (*portPriv->AdaptorRec->StopVideo)(
- portPriv->pScrn, portPriv->DevPriv.ptr, FALSE);
- portPriv->isOn = XV_PENDING;
- }
-
- /* This clip was copied and only good for one shot */
- if(!portPriv->FreeCompositeClip)
- portPriv->pCompositeClip = NULL;
-
- RegionUninit(&WinRegion);
- RegionUninit(&ClipRegion);
-
- return ret;
-}
-
-
-static int
-xf86XVReputVideo(XvPortRecPrivatePtr portPriv)
-{
- RegionRec WinRegion;
- RegionRec ClipRegion;
- BoxRec WinBox;
- int ret = Success;
- Bool clippedAway = FALSE;
-
- xf86XVUpdateCompositeClip(portPriv);
-
- /* translate the video region to the screen */
- WinBox.x1 = portPriv->pDraw->x + portPriv->drw_x;
- WinBox.y1 = portPriv->pDraw->y + portPriv->drw_y;
- WinBox.x2 = WinBox.x1 + portPriv->drw_w;
- WinBox.y2 = WinBox.y1 + portPriv->drw_h;
-
- /* clip to the window composite clip */
- RegionInit(&WinRegion, &WinBox, 1);
- RegionNull(&ClipRegion);
- RegionIntersect(&ClipRegion, &WinRegion, portPriv->pCompositeClip);
-
- /* clip and translate to the viewport */
- if(portPriv->AdaptorRec->flags & VIDEO_CLIP_TO_VIEWPORT) {
- RegionRec VPReg;
- BoxRec VPBox;
-
- VPBox.x1 = portPriv->pScrn->frameX0;
- VPBox.y1 = portPriv->pScrn->frameY0;
- VPBox.x2 = portPriv->pScrn->frameX1 + 1;
- VPBox.y2 = portPriv->pScrn->frameY1 + 1;
-
- RegionInit(&VPReg, &VPBox, 1);
- RegionIntersect(&ClipRegion, &ClipRegion, &VPReg);
- RegionUninit(&VPReg);
- }
-
- /* that's all if it's totally obscured */
- if(!RegionNotEmpty(&ClipRegion)) {
- clippedAway = TRUE;
- goto CLIP_VIDEO_BAILOUT;
- }
-
- /* bailout if we have to clip but the hardware doesn't support it */
- if(portPriv->AdaptorRec->flags & VIDEO_NO_CLIPPING) {
- BoxPtr clipBox = RegionRects(&ClipRegion);
- if( (RegionNumRects(&ClipRegion) != 1) ||
- (clipBox->x1 != WinBox.x1) || (clipBox->x2 != WinBox.x2) ||
- (clipBox->y1 != WinBox.y1) || (clipBox->y2 != WinBox.y2))
- {
- clippedAway = TRUE;
- goto CLIP_VIDEO_BAILOUT;
- }
- }
-
- if(portPriv->AdaptorRec->flags & VIDEO_INVERT_CLIPLIST) {
- RegionSubtract(&ClipRegion, &WinRegion, &ClipRegion);
- }
-
- ret = (*portPriv->AdaptorRec->PutVideo)(portPriv->pScrn,
- portPriv->vid_x, portPriv->vid_y,
- WinBox.x1, WinBox.y1,
- portPriv->vid_w, portPriv->vid_h,
- portPriv->drw_w, portPriv->drw_h,
- &ClipRegion, portPriv->DevPriv.ptr,
- portPriv->pDraw);
-
- if(ret == Success) portPriv->isOn = XV_ON;
-
-CLIP_VIDEO_BAILOUT:
-
- if((clippedAway || (ret != Success)) && (portPriv->isOn == XV_ON)) {
- (*portPriv->AdaptorRec->StopVideo)(
- portPriv->pScrn, portPriv->DevPriv.ptr, FALSE);
- portPriv->isOn = XV_PENDING;
- }
-
- /* This clip was copied and only good for one shot */
- if(!portPriv->FreeCompositeClip)
- portPriv->pCompositeClip = NULL;
-
- RegionUninit(&WinRegion);
- RegionUninit(&ClipRegion);
-
- return ret;
-}
-
-/* Reput image/still */
-static int
-xf86XVReputImage(XvPortRecPrivatePtr portPriv)
-{
- RegionRec WinRegion;
- RegionRec ClipRegion;
- BoxRec WinBox;
- int ret = Success;
- Bool clippedAway = FALSE;
-
- xf86XVUpdateCompositeClip(portPriv);
-
- /* the clip can get smaller over time */
- RegionCopy(portPriv->clientClip, portPriv->pCompositeClip);
- RegionTranslate(portPriv->clientClip,
- -portPriv->pDraw->x, -portPriv->pDraw->y);
-
- /* translate the video region to the screen */
- WinBox.x1 = portPriv->pDraw->x + portPriv->drw_x;
- WinBox.y1 = portPriv->pDraw->y + portPriv->drw_y;
- WinBox.x2 = WinBox.x1 + portPriv->drw_w;
- WinBox.y2 = WinBox.y1 + portPriv->drw_h;
-
- /* clip to the window composite clip */
- RegionInit(&WinRegion, &WinBox, 1);
- RegionNull(&ClipRegion);
- RegionIntersect(&ClipRegion, &WinRegion, portPriv->pCompositeClip);
-
- /* clip and translate to the viewport */
- if(portPriv->AdaptorRec->flags & VIDEO_CLIP_TO_VIEWPORT) {
- RegionRec VPReg;
- BoxRec VPBox;
-
- VPBox.x1 = portPriv->pScrn->frameX0;
- VPBox.y1 = portPriv->pScrn->frameY0;
- VPBox.x2 = portPriv->pScrn->frameX1 + 1;
- VPBox.y2 = portPriv->pScrn->frameY1 + 1;
-
- RegionInit(&VPReg, &VPBox, 1);
- RegionIntersect(&ClipRegion, &ClipRegion, &VPReg);
- RegionUninit(&VPReg);
- }
-
- /* that's all if it's totally obscured */
- if(!RegionNotEmpty(&ClipRegion)) {
- clippedAway = TRUE;
- goto CLIP_VIDEO_BAILOUT;
- }
-
- /* bailout if we have to clip but the hardware doesn't support it */
- if(portPriv->AdaptorRec->flags & VIDEO_NO_CLIPPING) {
- BoxPtr clipBox = RegionRects(&ClipRegion);
- if( (RegionNumRects(&ClipRegion) != 1) ||
- (clipBox->x1 != WinBox.x1) || (clipBox->x2 != WinBox.x2) ||
- (clipBox->y1 != WinBox.y1) || (clipBox->y2 != WinBox.y2))
- {
- clippedAway = TRUE;
- goto CLIP_VIDEO_BAILOUT;
- }
- }
-
- if(portPriv->AdaptorRec->flags & VIDEO_INVERT_CLIPLIST) {
- RegionSubtract(&ClipRegion, &WinRegion, &ClipRegion);
- }
-
- ret = (*portPriv->AdaptorRec->ReputImage)(portPriv->pScrn,
- portPriv->vid_x, portPriv->vid_y,
- WinBox.x1, WinBox.y1,
- portPriv->vid_w, portPriv->vid_h,
- portPriv->drw_w, portPriv->drw_h,
- &ClipRegion, portPriv->DevPriv.ptr,
- portPriv->pDraw);
-
- portPriv->isOn = (ret == Success) ? XV_ON : XV_OFF;
-
-CLIP_VIDEO_BAILOUT:
-
- if((clippedAway || (ret != Success)) && (portPriv->isOn == XV_ON)) {
- (*portPriv->AdaptorRec->StopVideo)(
- portPriv->pScrn, portPriv->DevPriv.ptr, FALSE);
- portPriv->isOn = XV_PENDING;
- }
-
- /* This clip was copied and only good for one shot */
- if(!portPriv->FreeCompositeClip)
- portPriv->pCompositeClip = NULL;
-
- RegionUninit(&WinRegion);
- RegionUninit(&ClipRegion);
-
- return ret;
-}
-
-
-static int
-xf86XVReputAllVideo(WindowPtr pWin, pointer data)
-{
- XF86XVWindowPtr WinPriv = GET_XF86XV_WINDOW(pWin);
-
- while(WinPriv) {
- if(WinPriv->PortRec->type == XvInputMask)
- xf86XVReputVideo(WinPriv->PortRec);
- else
- xf86XVRegetVideo(WinPriv->PortRec);
- WinPriv = WinPriv->next;
- }
-
- return WT_WALKCHILDREN;
-}
-
-static int
-xf86XVEnlistPortInWindow(WindowPtr pWin, XvPortRecPrivatePtr portPriv)
-{
- XF86XVWindowPtr winPriv, PrivRoot;
-
- winPriv = PrivRoot = GET_XF86XV_WINDOW(pWin);
-
- /* Enlist our port in the window private */
- while(winPriv) {
- if(winPriv->PortRec == portPriv) /* we're already listed */
- break;
- winPriv = winPriv->next;
- }
-
- if(!winPriv) {
- winPriv = calloc(1, sizeof(XF86XVWindowRec));
- if(!winPriv) return BadAlloc;
- winPriv->PortRec = portPriv;
- winPriv->next = PrivRoot;
- dixSetPrivate(&pWin->devPrivates, XF86XVWindowKey, winPriv);
- }
-
- portPriv->pDraw = (DrawablePtr)pWin;
-
- return Success;
-}
-
-
-static void
-xf86XVRemovePortFromWindow(WindowPtr pWin, XvPortRecPrivatePtr portPriv)
-{
- XF86XVWindowPtr winPriv, prevPriv = NULL;
- winPriv = GET_XF86XV_WINDOW(pWin);
-
- while(winPriv) {
- if(winPriv->PortRec == portPriv) {
- if(prevPriv)
- prevPriv->next = winPriv->next;
- else
- dixSetPrivate(&pWin->devPrivates, XF86XVWindowKey,
- winPriv->next);
- free(winPriv);
- break;
- }
- prevPriv = winPriv;
- winPriv = winPriv->next;
- }
- portPriv->pDraw = NULL;
- if (portPriv->ckeyFilled) {
- RegionDestroy(portPriv->ckeyFilled);
- portPriv->ckeyFilled = NULL;
- }
- portPriv->clipChanged = FALSE;
-}
-
-static void
-xf86XVReputOrStopPort(XvPortRecPrivatePtr pPriv,
- WindowPtr pWin,
- Bool visible)
-{
- if (!visible) {
- if (pPriv->isOn == XV_ON) {
- (*pPriv->AdaptorRec->StopVideo)(pPriv->pScrn, pPriv->DevPriv.ptr, FALSE);
- pPriv->isOn = XV_PENDING;
- }
-
- if (!pPriv->type) /* overlaid still/image*/
- xf86XVRemovePortFromWindow(pWin, pPriv);
-
- return;
- }
-
- switch (pPriv->type) {
- case XvInputMask:
- xf86XVReputVideo(pPriv);
- break;
- case XvOutputMask:
- xf86XVRegetVideo(pPriv);
- break;
- default: /* overlaid still/image*/
- if (pPriv->AdaptorRec->ReputImage)
- xf86XVReputImage(pPriv);
- break;
- }
-}
-
-static void
-xf86XVReputOrStopAllPorts(ScrnInfoPtr pScrn, Bool onlyChanged)
-{
- ScreenPtr pScreen = pScrn->pScreen;
- XvScreenPtr pxvs = GET_XV_SCREEN(pScreen);
- XvAdaptorPtr pa;
- int c, i;
-
- for (c = pxvs->nAdaptors, pa = pxvs->pAdaptors; c > 0; c--, pa++) {
- XvPortPtr pPort = pa->pPorts;
-
- for (i = pa->nPorts; i > 0; i--, pPort++) {
- XvPortRecPrivatePtr pPriv = (XvPortRecPrivatePtr)pPort->devPriv.ptr;
- WindowPtr pWin = (WindowPtr)pPriv->pDraw;
- Bool visible;
-
- if (pPriv->isOn == XV_OFF || !pWin)
- continue;
-
- if (onlyChanged && !pPriv->clipChanged)
- continue;
-
- visible = pWin->visibility == VisibilityUnobscured ||
- pWin->visibility == VisibilityPartiallyObscured;
-
- /*
- * Stop and remove still/images if
- * ReputImage isn't supported.
- */
- if (!pPriv->type && !pPriv->AdaptorRec->ReputImage)
- visible = FALSE;
-
- xf86XVReputOrStopPort(pPriv, pWin, visible);
-
- pPriv->clipChanged = FALSE;
- }
- }
-}
-
-/**** ScreenRec fields ****/
-
-static Bool
-xf86XVDestroyWindow(WindowPtr pWin)
-{
- ScreenPtr pScreen = pWin->drawable.pScreen;
- XF86XVScreenPtr ScreenPriv = GET_XF86XV_SCREEN(pScreen);
- XF86XVWindowPtr tmp, WinPriv = GET_XF86XV_WINDOW(pWin);
- int ret;
-
- while(WinPriv) {
- XvPortRecPrivatePtr pPriv = WinPriv->PortRec;
-
- if(pPriv->isOn > XV_OFF) {
- (*pPriv->AdaptorRec->StopVideo)(
- pPriv->pScrn, pPriv->DevPriv.ptr, TRUE);
- pPriv->isOn = XV_OFF;
- }
-
- pPriv->pDraw = NULL;
- tmp = WinPriv;
- WinPriv = WinPriv->next;
- free(tmp);
- }
-
- dixSetPrivate(&pWin->devPrivates, XF86XVWindowKey, NULL);
-
- pScreen->DestroyWindow = ScreenPriv->DestroyWindow;
- ret = (*pScreen->DestroyWindow)(pWin);
- pScreen->DestroyWindow = xf86XVDestroyWindow;
-
- return ret;
-}
-
-static void
-xf86XVPostValidateTree(WindowPtr pWin, WindowPtr pLayerWin, VTKind kind)
-{
- ScreenPtr pScreen;
- XF86XVScreenPtr ScreenPriv;
- ScrnInfoPtr pScrn;
-
- if (pWin)
- pScreen = pWin->drawable.pScreen;
- else
- pScreen = pLayerWin->drawable.pScreen;
-
- ScreenPriv = GET_XF86XV_SCREEN(pScreen);
- pScrn = xf86Screens[pScreen->myNum];
-
- xf86XVReputOrStopAllPorts(pScrn, TRUE);
-
- pScreen->PostValidateTree = ScreenPriv->PostValidateTree;
- if (pScreen->PostValidateTree) {
- (*pScreen->PostValidateTree)(pWin, pLayerWin, kind);
- }
- ScreenPriv->PostValidateTree = PostValidateTreeUndefined;
-}
-
-static void
-xf86XVWindowExposures(WindowPtr pWin, RegionPtr reg1, RegionPtr reg2)
-{
- ScreenPtr pScreen = pWin->drawable.pScreen;
- XF86XVScreenPtr ScreenPriv = GET_XF86XV_SCREEN(pScreen);
- XF86XVWindowPtr WinPriv = GET_XF86XV_WINDOW(pWin);
- XvPortRecPrivatePtr pPriv;
- Bool AreasExposed;
-
- AreasExposed = (WinPriv && reg1 && RegionNotEmpty(reg1));
-
- pScreen->WindowExposures = ScreenPriv->WindowExposures;
- (*pScreen->WindowExposures)(pWin, reg1, reg2);
- pScreen->WindowExposures = xf86XVWindowExposures;
-
- /* filter out XClearWindow/Area */
- if (!pWin->valdata) return;
-
- while(WinPriv) {
- Bool visible = TRUE;
-
- pPriv = WinPriv->PortRec;
-
- /*
- * Stop and remove still/images if areas were exposed and
- * ReputImage isn't supported.
- */
- if (!pPriv->type && !pPriv->AdaptorRec->ReputImage)
- visible = !AreasExposed;
-
- /*
- * Subtract exposed areas from overlaid image to match textured video
- * behavior.
- */
- if (!pPriv->type && pPriv->clientClip)
- RegionSubtract(pPriv->clientClip, pPriv->clientClip, reg1);
-
- if (visible && pPriv->ckeyFilled) {
- RegionRec tmp;
- RegionNull(&tmp);
- RegionCopy(&tmp, reg1);
- RegionTranslate(&tmp, pWin->drawable.x, pWin->drawable.y);
- RegionSubtract(pPriv->ckeyFilled, pPriv->ckeyFilled, &tmp);
- }
-
- WinPriv = WinPriv->next;
- xf86XVReputOrStopPort(pPriv, pWin, visible);
-
- pPriv->clipChanged = FALSE;
- }
-}
-
-static void
-xf86XVClipNotify(WindowPtr pWin, int dx, int dy)
-{
- ScreenPtr pScreen = pWin->drawable.pScreen;
- XF86XVScreenPtr ScreenPriv = GET_XF86XV_SCREEN(pScreen);
- XF86XVWindowPtr WinPriv = GET_XF86XV_WINDOW(pWin);
- XvPortRecPrivatePtr pPriv;
-
- while(WinPriv) {
- pPriv = WinPriv->PortRec;
-
- if(pPriv->pCompositeClip && pPriv->FreeCompositeClip)
- RegionDestroy(pPriv->pCompositeClip);
-
- pPriv->pCompositeClip = NULL;
-
- if (pPriv->AdaptorRec->ClipNotify)
- (*pPriv->AdaptorRec->ClipNotify)(pPriv->pScrn, pPriv->DevPriv.ptr,
- pWin, dx, dy);
-
- pPriv->clipChanged = TRUE;
-
- if (ScreenPriv->PostValidateTree == PostValidateTreeUndefined) {
- ScreenPriv->PostValidateTree = pScreen->PostValidateTree;
- pScreen->PostValidateTree = xf86XVPostValidateTree;
- }
-
- WinPriv = WinPriv->next;
- }
-
- if(ScreenPriv->ClipNotify) {
- pScreen->ClipNotify = ScreenPriv->ClipNotify;
- (*pScreen->ClipNotify)(pWin, dx, dy);
- pScreen->ClipNotify = xf86XVClipNotify;
- }
-}
-
-
-
-/**** Required XvScreenRec fields ****/
-
-static Bool
-xf86XVCloseScreen(int i, ScreenPtr pScreen)
-{
- ScrnInfoPtr pScrn = xf86Screens[pScreen->myNum];
- XvScreenPtr pxvs = GET_XV_SCREEN(pScreen);
- XF86XVScreenPtr ScreenPriv = GET_XF86XV_SCREEN(pScreen);
- XvAdaptorPtr pa;
- int c;
-
- if(!ScreenPriv) return TRUE;
-
- pScreen->DestroyWindow = ScreenPriv->DestroyWindow;
- pScreen->WindowExposures = ScreenPriv->WindowExposures;
- pScreen->ClipNotify = ScreenPriv->ClipNotify;
-
- pScrn->EnterVT = ScreenPriv->EnterVT;
- pScrn->LeaveVT = ScreenPriv->LeaveVT;
- pScrn->AdjustFrame = ScreenPriv->AdjustFrame;
- pScrn->ModeSet = ScreenPriv->ModeSet;
-
- for(c = 0, pa = pxvs->pAdaptors; c < pxvs->nAdaptors; c++, pa++) {
- xf86XVFreeAdaptor(pa);
- }
-
- free(pxvs->pAdaptors);
- free(ScreenPriv);
- return TRUE;
-}
-
-
-static int
-xf86XVQueryAdaptors(
- ScreenPtr pScreen,
- XvAdaptorPtr *p_pAdaptors,
- int *p_nAdaptors
-){
- XvScreenPtr pxvs = GET_XV_SCREEN(pScreen);
-
- *p_nAdaptors = pxvs->nAdaptors;
- *p_pAdaptors = pxvs->pAdaptors;
-
- return Success;
-}
-
-
-/**** ScrnInfoRec fields ****/
-
-static Bool
-xf86XVEnterVT(int index, int flags)
-{
- ScrnInfoPtr pScrn = xf86Screens[index];
- ScreenPtr pScreen = screenInfo.screens[index];
- XF86XVScreenPtr ScreenPriv = GET_XF86XV_SCREEN(pScreen);
- Bool ret;
-
- pScrn->EnterVT = ScreenPriv->EnterVT;
- ret = (*ScreenPriv->EnterVT)(index, flags);
- ScreenPriv->EnterVT = pScrn->EnterVT;
- pScrn->EnterVT = xf86XVEnterVT;
-
- if(ret) WalkTree(pScreen, xf86XVReputAllVideo, 0);
-
- return ret;
-}
-
-static void
-xf86XVLeaveVT(int index, int flags)
-{
- ScrnInfoPtr pScrn = xf86Screens[index];
- ScreenPtr pScreen = screenInfo.screens[index];
- XvScreenPtr pxvs = GET_XV_SCREEN(pScreen);
- XF86XVScreenPtr ScreenPriv = GET_XF86XV_SCREEN(pScreen);
- XvAdaptorPtr pAdaptor;
- XvPortPtr pPort;
- XvPortRecPrivatePtr pPriv;
- int i, j;
-
- for(i = 0; i < pxvs->nAdaptors; i++) {
- pAdaptor = &pxvs->pAdaptors[i];
- for(j = 0; j < pAdaptor->nPorts; j++) {
- pPort = &pAdaptor->pPorts[j];
- pPriv = (XvPortRecPrivatePtr)pPort->devPriv.ptr;
- if(pPriv->isOn > XV_OFF) {
-
- (*pPriv->AdaptorRec->StopVideo)(
- pPriv->pScrn, pPriv->DevPriv.ptr, TRUE);
- pPriv->isOn = XV_OFF;
-
- if(pPriv->pCompositeClip && pPriv->FreeCompositeClip)
- RegionDestroy(pPriv->pCompositeClip);
-
- pPriv->pCompositeClip = NULL;
-
- if(!pPriv->type && pPriv->pDraw) { /* still */
- xf86XVRemovePortFromWindow((WindowPtr)pPriv->pDraw, pPriv);
- }
- }
- }
- }
-
- pScrn->LeaveVT = ScreenPriv->LeaveVT;
- (*ScreenPriv->LeaveVT)(index, flags);
- ScreenPriv->LeaveVT = pScrn->LeaveVT;
- pScrn->LeaveVT = xf86XVLeaveVT;
-}
-
-static void
-xf86XVAdjustFrame(int index, int x, int y, int flags)
-{
- ScrnInfoPtr pScrn = xf86Screens[index];
- ScreenPtr pScreen = pScrn->pScreen;
- XF86XVScreenPtr ScreenPriv = GET_XF86XV_SCREEN(pScreen);
-
- if(ScreenPriv->AdjustFrame) {
- pScrn->AdjustFrame = ScreenPriv->AdjustFrame;
- (*pScrn->AdjustFrame)(index, x, y, flags);
- pScrn->AdjustFrame = xf86XVAdjustFrame;
- }
-
- xf86XVReputOrStopAllPorts(pScrn, FALSE);
-}
-
-static void
-xf86XVModeSet(ScrnInfoPtr pScrn)
-{
- ScreenPtr pScreen = pScrn->pScreen;
- XF86XVScreenPtr ScreenPriv;
-
- /* Can be called before pScrn->pScreen is set */
- if (!pScreen)
- return;
-
- ScreenPriv = GET_XF86XV_SCREEN(pScreen);
-
- if (ScreenPriv->ModeSet) {
- pScrn->ModeSet = ScreenPriv->ModeSet;
- (*pScrn->ModeSet)(pScrn);
- pScrn->ModeSet = xf86XVModeSet;
- }
-
- xf86XVReputOrStopAllPorts(pScrn, FALSE);
-}
-
-/**** XvAdaptorRec fields ****/
-
-static int
-xf86XVAllocatePort(
- unsigned long port,
- XvPortPtr pPort,
- XvPortPtr *ppPort
-){
- *ppPort = pPort;
- return Success;
-}
-
-
-
-static int
-xf86XVFreePort(XvPortPtr pPort)
-{
- return Success;
-}
-
-
-static int
-xf86XVPutVideo(
- ClientPtr client,
- DrawablePtr pDraw,
- XvPortPtr pPort,
- GCPtr pGC,
- INT16 vid_x, INT16 vid_y,
- CARD16 vid_w, CARD16 vid_h,
- INT16 drw_x, INT16 drw_y,
- CARD16 drw_w, CARD16 drw_h
-){
- XvPortRecPrivatePtr portPriv = (XvPortRecPrivatePtr)(pPort->devPriv.ptr);
- int result;
-
- /* No dumping video to pixmaps... For now anyhow */
- if(pDraw->type != DRAWABLE_WINDOW) {
- pPort->pDraw = (DrawablePtr)NULL;
- return BadAlloc;
- }
-
- /* If we are changing windows, unregister our port in the old window */
- if(portPriv->pDraw && (portPriv->pDraw != pDraw))
- xf86XVRemovePortFromWindow((WindowPtr)(portPriv->pDraw), portPriv);
-
- /* Register our port with the new window */
- result = xf86XVEnlistPortInWindow((WindowPtr)pDraw, portPriv);
- if(result != Success) return result;
-
- portPriv->type = XvInputMask;
-
- /* save a copy of these parameters */
- portPriv->vid_x = vid_x; portPriv->vid_y = vid_y;
- portPriv->vid_w = vid_w; portPriv->vid_h = vid_h;
- portPriv->drw_x = drw_x; portPriv->drw_y = drw_y;
- portPriv->drw_w = drw_w; portPriv->drw_h = drw_h;
-
- /* make sure we have the most recent copy of the clientClip */
- xf86XVCopyClip(portPriv, pGC);
-
- /* To indicate to the DI layer that we were successful */
- pPort->pDraw = pDraw;
-
- if(!portPriv->pScrn->vtSema) return Success; /* Success ? */
-
- return(xf86XVReputVideo(portPriv));
-}
-
-static int
-xf86XVPutStill(
- ClientPtr client,
- DrawablePtr pDraw,
- XvPortPtr pPort,
- GCPtr pGC,
- INT16 vid_x, INT16 vid_y,
- CARD16 vid_w, CARD16 vid_h,
- INT16 drw_x, INT16 drw_y,
- CARD16 drw_w, CARD16 drw_h
-){
- XvPortRecPrivatePtr portPriv = (XvPortRecPrivatePtr)(pPort->devPriv.ptr);
- RegionRec WinRegion;
- RegionRec ClipRegion;
- BoxRec WinBox;
- int ret = Success;
- Bool clippedAway = FALSE;
-
- if (pDraw->type != DRAWABLE_WINDOW)
- return BadAlloc;
-
- if(!portPriv->pScrn->vtSema) return Success; /* Success ? */
-
- WinBox.x1 = pDraw->x + drw_x;
- WinBox.y1 = pDraw->y + drw_y;
- WinBox.x2 = WinBox.x1 + drw_w;
- WinBox.y2 = WinBox.y1 + drw_h;
-
- xf86XVCopyCompositeClip(portPriv, pGC, pDraw);
-
- RegionInit(&WinRegion, &WinBox, 1);
- RegionNull(&ClipRegion);
- RegionIntersect(&ClipRegion, &WinRegion, pGC->pCompositeClip);
-
- if(portPriv->AdaptorRec->flags & VIDEO_CLIP_TO_VIEWPORT) {
- RegionRec VPReg;
- BoxRec VPBox;
-
- VPBox.x1 = portPriv->pScrn->frameX0;
- VPBox.y1 = portPriv->pScrn->frameY0;
- VPBox.x2 = portPriv->pScrn->frameX1 + 1;
- VPBox.y2 = portPriv->pScrn->frameY1 + 1;
-
- RegionInit(&VPReg, &VPBox, 1);
- RegionIntersect(&ClipRegion, &ClipRegion, &VPReg);
- RegionUninit(&VPReg);
- }
-
- if(portPriv->pDraw) {
- xf86XVRemovePortFromWindow((WindowPtr)(portPriv->pDraw), portPriv);
- }
-
- if(!RegionNotEmpty(&ClipRegion)) {
- clippedAway = TRUE;
- goto PUT_STILL_BAILOUT;
- }
-
- if(portPriv->AdaptorRec->flags & VIDEO_NO_CLIPPING) {
- BoxPtr clipBox = RegionRects(&ClipRegion);
- if( (RegionNumRects(&ClipRegion) != 1) ||
- (clipBox->x1 != WinBox.x1) || (clipBox->x2 != WinBox.x2) ||
- (clipBox->y1 != WinBox.y1) || (clipBox->y2 != WinBox.y2))
- {
- clippedAway = TRUE;
- goto PUT_STILL_BAILOUT;
- }
- }
-
- if(portPriv->AdaptorRec->flags & VIDEO_INVERT_CLIPLIST) {
- RegionSubtract(&ClipRegion, &WinRegion, &ClipRegion);
- }
-
- ret = (*portPriv->AdaptorRec->PutStill)(portPriv->pScrn,
- vid_x, vid_y, WinBox.x1, WinBox.y1,
- vid_w, vid_h, drw_w, drw_h,
- &ClipRegion, portPriv->DevPriv.ptr,
- pDraw);
-
- if((ret == Success) &&
- (portPriv->AdaptorRec->flags & VIDEO_OVERLAID_STILLS)) {
-
- xf86XVEnlistPortInWindow((WindowPtr)pDraw, portPriv);
- portPriv->isOn = XV_ON;
- portPriv->vid_x = vid_x; portPriv->vid_y = vid_y;
- portPriv->vid_w = vid_w; portPriv->vid_h = vid_h;
- portPriv->drw_x = drw_x; portPriv->drw_y = drw_y;
- portPriv->drw_w = drw_w; portPriv->drw_h = drw_h;
- portPriv->type = 0; /* no mask means it's transient and should
- not be reput once it's removed */
- pPort->pDraw = pDraw; /* make sure we can get stop requests */
- }
-
-PUT_STILL_BAILOUT:
-
- if((clippedAway || (ret != Success)) && (portPriv->isOn == XV_ON)) {
- (*portPriv->AdaptorRec->StopVideo)(
- portPriv->pScrn, portPriv->DevPriv.ptr, FALSE);
- portPriv->isOn = XV_PENDING;
- }
-
- /* This clip was copied and only good for one shot */
- if(!portPriv->FreeCompositeClip)
- portPriv->pCompositeClip = NULL;
-
- RegionUninit(&WinRegion);
- RegionUninit(&ClipRegion);
-
- return ret;
-}
-
-static int
-xf86XVGetVideo(
- ClientPtr client,
- DrawablePtr pDraw,
- XvPortPtr pPort,
- GCPtr pGC,
- INT16 vid_x, INT16 vid_y,
- CARD16 vid_w, CARD16 vid_h,
- INT16 drw_x, INT16 drw_y,
- CARD16 drw_w, CARD16 drw_h
-){
- XvPortRecPrivatePtr portPriv = (XvPortRecPrivatePtr)(pPort->devPriv.ptr);
- int result;
-
- /* No pixmaps... For now anyhow */
- if(pDraw->type != DRAWABLE_WINDOW) {
- pPort->pDraw = (DrawablePtr)NULL;
- return BadAlloc;
- }
-
- /* If we are changing windows, unregister our port in the old window */
- if(portPriv->pDraw && (portPriv->pDraw != pDraw))
- xf86XVRemovePortFromWindow((WindowPtr)(portPriv->pDraw), portPriv);
-
- /* Register our port with the new window */
- result = xf86XVEnlistPortInWindow((WindowPtr)pDraw, portPriv);
- if(result != Success) return result;
-
- portPriv->type = XvOutputMask;
-
- /* save a copy of these parameters */
- portPriv->vid_x = vid_x; portPriv->vid_y = vid_y;
- portPriv->vid_w = vid_w; portPriv->vid_h = vid_h;
- portPriv->drw_x = drw_x; portPriv->drw_y = drw_y;
- portPriv->drw_w = drw_w; portPriv->drw_h = drw_h;
-
- /* make sure we have the most recent copy of the clientClip */
- xf86XVCopyClip(portPriv, pGC);
-
- /* To indicate to the DI layer that we were successful */
- pPort->pDraw = pDraw;
-
- if(!portPriv->pScrn->vtSema) return Success; /* Success ? */
-
- return(xf86XVRegetVideo(portPriv));
-}
-
-static int
-xf86XVGetStill(
- ClientPtr client,
- DrawablePtr pDraw,
- XvPortPtr pPort,
- GCPtr pGC,
- INT16 vid_x, INT16 vid_y,
- CARD16 vid_w, CARD16 vid_h,
- INT16 drw_x, INT16 drw_y,
- CARD16 drw_w, CARD16 drw_h
-){
- XvPortRecPrivatePtr portPriv = (XvPortRecPrivatePtr)(pPort->devPriv.ptr);
- RegionRec WinRegion;
- RegionRec ClipRegion;
- BoxRec WinBox;
- int ret = Success;
- Bool clippedAway = FALSE;
-
- if (pDraw->type != DRAWABLE_WINDOW)
- return BadAlloc;
-
- if(!portPriv->pScrn->vtSema) return Success; /* Success ? */
-
- WinBox.x1 = pDraw->x + drw_x;
- WinBox.y1 = pDraw->y + drw_y;
- WinBox.x2 = WinBox.x1 + drw_w;
- WinBox.y2 = WinBox.y1 + drw_h;
-
- RegionInit(&WinRegion, &WinBox, 1);
- RegionNull(&ClipRegion);
- RegionIntersect(&ClipRegion, &WinRegion, pGC->pCompositeClip);
-
- if(portPriv->pDraw) {
- xf86XVRemovePortFromWindow((WindowPtr)(portPriv->pDraw), portPriv);
- }
-
- if(!RegionNotEmpty(&ClipRegion)) {
- clippedAway = TRUE;
- goto GET_STILL_BAILOUT;
- }
-
- if(portPriv->AdaptorRec->flags & VIDEO_INVERT_CLIPLIST) {
- RegionSubtract(&ClipRegion, &WinRegion, &ClipRegion);
- }
-
- ret = (*portPriv->AdaptorRec->GetStill)(portPriv->pScrn,
- vid_x, vid_y, WinBox.x1, WinBox.y1,
- vid_w, vid_h, drw_w, drw_h,
- &ClipRegion, portPriv->DevPriv.ptr,
- pDraw);
-
-GET_STILL_BAILOUT:
-
- if((clippedAway || (ret != Success)) && (portPriv->isOn == XV_ON)) {
- (*portPriv->AdaptorRec->StopVideo)(
- portPriv->pScrn, portPriv->DevPriv.ptr, FALSE);
- portPriv->isOn = XV_PENDING;
- }
-
- RegionUninit(&WinRegion);
- RegionUninit(&ClipRegion);
-
- return ret;
-}
-
-
-
-static int
-xf86XVStopVideo(
- ClientPtr client,
- XvPortPtr pPort,
- DrawablePtr pDraw
-){
- XvPortRecPrivatePtr portPriv = (XvPortRecPrivatePtr)(pPort->devPriv.ptr);
-
- if(pDraw->type != DRAWABLE_WINDOW)
- return BadAlloc;
-
- xf86XVRemovePortFromWindow((WindowPtr)pDraw, portPriv);
-
- if(!portPriv->pScrn->vtSema) return Success; /* Success ? */
-
- /* Must free resources. */
-
- if(portPriv->isOn > XV_OFF) {
- (*portPriv->AdaptorRec->StopVideo)(
- portPriv->pScrn, portPriv->DevPriv.ptr, TRUE);
- portPriv->isOn = XV_OFF;
- }
-
- return Success;
-}
-
-static int
-xf86XVSetPortAttribute(
- ClientPtr client,
- XvPortPtr pPort,
- Atom attribute,
- INT32 value
-){
- XvPortRecPrivatePtr portPriv = (XvPortRecPrivatePtr)(pPort->devPriv.ptr);
-
- return((*portPriv->AdaptorRec->SetPortAttribute)(portPriv->pScrn,
- attribute, value, portPriv->DevPriv.ptr));
-}
-
-
-static int
-xf86XVGetPortAttribute(
- ClientPtr client,
- XvPortPtr pPort,
- Atom attribute,
- INT32 *p_value
-){
- XvPortRecPrivatePtr portPriv = (XvPortRecPrivatePtr)(pPort->devPriv.ptr);
-
- return((*portPriv->AdaptorRec->GetPortAttribute)(portPriv->pScrn,
- attribute, p_value, portPriv->DevPriv.ptr));
-}
-
-
-
-static int
-xf86XVQueryBestSize(
- ClientPtr client,
- XvPortPtr pPort,
- CARD8 motion,
- CARD16 vid_w, CARD16 vid_h,
- CARD16 drw_w, CARD16 drw_h,
- unsigned int *p_w, unsigned int *p_h
-){
- XvPortRecPrivatePtr portPriv = (XvPortRecPrivatePtr)(pPort->devPriv.ptr);
-
- (*portPriv->AdaptorRec->QueryBestSize)(portPriv->pScrn,
- (Bool)motion, vid_w, vid_h, drw_w, drw_h,
- p_w, p_h, portPriv->DevPriv.ptr);
-
- return Success;
-}
-
-
-static int
-xf86XVPutImage(
- ClientPtr client,
- DrawablePtr pDraw,
- XvPortPtr pPort,
- GCPtr pGC,
- INT16 src_x, INT16 src_y,
- CARD16 src_w, CARD16 src_h,
- INT16 drw_x, INT16 drw_y,
- CARD16 drw_w, CARD16 drw_h,
- XvImagePtr format,
- unsigned char* data,
- Bool sync,
- CARD16 width, CARD16 height
-){
- XvPortRecPrivatePtr portPriv = (XvPortRecPrivatePtr)(pPort->devPriv.ptr);
- RegionRec WinRegion;
- RegionRec ClipRegion;
- BoxRec WinBox;
- int ret = Success;
- Bool clippedAway = FALSE;
-
- if (pDraw->type != DRAWABLE_WINDOW)
- return BadAlloc;
-
- if(!portPriv->pScrn->vtSema) return Success; /* Success ? */
-
- xf86XVCopyCompositeClip(portPriv, pGC, pDraw);
-
- WinBox.x1 = pDraw->x + drw_x;
- WinBox.y1 = pDraw->y + drw_y;
- WinBox.x2 = WinBox.x1 + drw_w;
- WinBox.y2 = WinBox.y1 + drw_h;
-
- RegionInit(&WinRegion, &WinBox, 1);
- RegionNull(&ClipRegion);
- RegionIntersect(&ClipRegion, &WinRegion, pGC->pCompositeClip);
-
- if(portPriv->AdaptorRec->flags & VIDEO_CLIP_TO_VIEWPORT) {
- RegionRec VPReg;
- BoxRec VPBox;
-
- VPBox.x1 = portPriv->pScrn->frameX0;
- VPBox.y1 = portPriv->pScrn->frameY0;
- VPBox.x2 = portPriv->pScrn->frameX1 + 1;
- VPBox.y2 = portPriv->pScrn->frameY1 + 1;
-
- RegionInit(&VPReg, &VPBox, 1);
- RegionIntersect(&ClipRegion, &ClipRegion, &VPReg);
- RegionUninit(&VPReg);
- }
-
- /* If we are changing windows, unregister our port in the old window */
- if(portPriv->pDraw && (portPriv->pDraw != pDraw))
- xf86XVRemovePortFromWindow((WindowPtr)(portPriv->pDraw), portPriv);
-
- /* Register our port with the new window */
- ret = xf86XVEnlistPortInWindow((WindowPtr)pDraw, portPriv);
- if(ret != Success) goto PUT_IMAGE_BAILOUT;
-
- if(!RegionNotEmpty(&ClipRegion)) {
- clippedAway = TRUE;
- goto PUT_IMAGE_BAILOUT;
- }
-
- if(portPriv->AdaptorRec->flags & VIDEO_NO_CLIPPING) {
- BoxPtr clipBox = RegionRects(&ClipRegion);
- if( (RegionNumRects(&ClipRegion) != 1) ||
- (clipBox->x1 != WinBox.x1) || (clipBox->x2 != WinBox.x2) ||
- (clipBox->y1 != WinBox.y1) || (clipBox->y2 != WinBox.y2))
- {
- clippedAway = TRUE;
- goto PUT_IMAGE_BAILOUT;
- }
- }
-
- if(portPriv->AdaptorRec->flags & VIDEO_INVERT_CLIPLIST) {
- RegionSubtract(&ClipRegion, &WinRegion, &ClipRegion);
- }
-
- ret = (*portPriv->AdaptorRec->PutImage)(portPriv->pScrn,
- src_x, src_y, WinBox.x1, WinBox.y1,
- src_w, src_h, drw_w, drw_h, format->id, data, width, height,
- sync, &ClipRegion, portPriv->DevPriv.ptr,
- pDraw);
-
- if((ret == Success) &&
- (portPriv->AdaptorRec->flags & VIDEO_OVERLAID_IMAGES)) {
-
- portPriv->isOn = XV_ON;
- portPriv->vid_x = src_x; portPriv->vid_y = src_y;
- portPriv->vid_w = src_w; portPriv->vid_h = src_h;
- portPriv->drw_x = drw_x; portPriv->drw_y = drw_y;
- portPriv->drw_w = drw_w; portPriv->drw_h = drw_h;
- portPriv->type = 0; /* no mask means it's transient and should
- not be reput once it's removed */
- pPort->pDraw = pDraw; /* make sure we can get stop requests */
- }
-
-PUT_IMAGE_BAILOUT:
-
- if((clippedAway || (ret != Success)) && (portPriv->isOn == XV_ON)) {
- (*portPriv->AdaptorRec->StopVideo)(
- portPriv->pScrn, portPriv->DevPriv.ptr, FALSE);
- portPriv->isOn = XV_PENDING;
- }
-
- /* This clip was copied and only good for one shot */
- if(!portPriv->FreeCompositeClip)
- portPriv->pCompositeClip = NULL;
-
- RegionUninit(&WinRegion);
- RegionUninit(&ClipRegion);
-
- return ret;
-}
-
-
-static int
-xf86XVQueryImageAttributes(
- ClientPtr client,
- XvPortPtr pPort,
- XvImagePtr format,
- CARD16 *width,
- CARD16 *height,
- int *pitches,
- int *offsets
-){
- XvPortRecPrivatePtr portPriv = (XvPortRecPrivatePtr)(pPort->devPriv.ptr);
-
- return (*portPriv->AdaptorRec->QueryImageAttributes)(portPriv->pScrn,
- format->id, width, height, pitches, offsets);
-}
-
-void
-xf86XVFillKeyHelperDrawable (DrawablePtr pDraw, CARD32 key, RegionPtr fillboxes)
-{
- ScreenPtr pScreen = pDraw->pScreen;
- ChangeGCVal pval[2];
- BoxPtr pbox = RegionRects(fillboxes);
- int i, nbox = RegionNumRects(fillboxes);
- xRectangle *rects;
- GCPtr gc;
-
- if(!xf86Screens[pScreen->myNum]->vtSema) return;
-
- gc = GetScratchGC(pDraw->depth, pScreen);
- pval[0].val = key;
- pval[1].val = IncludeInferiors;
- (void) ChangeGC(NullClient, gc, GCForeground|GCSubwindowMode, pval);
- ValidateGC(pDraw, gc);
-
- rects = malloc(nbox * sizeof(xRectangle));
-
- for(i = 0; i < nbox; i++, pbox++)
- {
- rects[i].x = pbox->x1 - pDraw->x;
- rects[i].y = pbox->y1 - pDraw->y;
- rects[i].width = pbox->x2 - pbox->x1;
- rects[i].height = pbox->y2 - pbox->y1;
- }
-
- (*gc->ops->PolyFillRect)(pDraw, gc, nbox, rects);
-
- free(rects);
- FreeScratchGC (gc);
-}
-
-void
-xf86XVFillKeyHelper (ScreenPtr pScreen, CARD32 key, RegionPtr fillboxes)
-{
- xf86XVFillKeyHelperDrawable (&pScreen->root->drawable, key, fillboxes);
-}
-
-void
-xf86XVFillKeyHelperPort (DrawablePtr pDraw, pointer data, CARD32 key, RegionPtr clipboxes, Bool fillEverything)
-{
- WindowPtr pWin = (WindowPtr)pDraw;
- XF86XVWindowPtr WinPriv = GET_XF86XV_WINDOW(pWin);
- XvPortRecPrivatePtr portPriv = NULL;
- RegionRec reg;
- RegionPtr fillboxes;
-
- while (WinPriv) {
- XvPortRecPrivatePtr pPriv = WinPriv->PortRec;
-
- if (data == pPriv->DevPriv.ptr) {
- portPriv = pPriv;
- break;
- }
-
- WinPriv = WinPriv->next;
- }
-
- if (!portPriv)
- return;
-
- if (!portPriv->ckeyFilled)
- portPriv->ckeyFilled = RegionCreate(NULL, 0);
-
- if (!fillEverything) {
- RegionNull(®);
- fillboxes = ®
- RegionSubtract(fillboxes, clipboxes, portPriv->ckeyFilled);
-
- if (!RegionNotEmpty(fillboxes))
- goto out;
- } else
- fillboxes = clipboxes;
-
-
- RegionCopy(portPriv->ckeyFilled, clipboxes);
-
- xf86XVFillKeyHelperDrawable(pDraw, key, fillboxes);
-out:
- if (!fillEverything)
- RegionUninit(®);
-}
-
-
-/* xf86XVClipVideoHelper -
-
- Takes the dst box in standard X BoxRec form (top and left
- edges inclusive, bottom and right exclusive). The new dst
- box is returned. The source boundaries are given (x1, y1
- inclusive, x2, y2 exclusive) and returned are the new source
- boundaries in 16.16 fixed point.
-*/
-
-Bool
-xf86XVClipVideoHelper(
- BoxPtr dst,
- INT32 *xa,
- INT32 *xb,
- INT32 *ya,
- INT32 *yb,
- RegionPtr reg,
- INT32 width,
- INT32 height
-){
- double xsw, xdw, ysw, ydw;
- INT32 delta;
- BoxPtr extents = RegionExtents(reg);
- int diff;
-
- xsw = (*xb - *xa) << 16;
- xdw = dst->x2 - dst->x1;
- ysw = (*yb - *ya) << 16;
- ydw = dst->y2 - dst->y1;
-
- *xa <<= 16; *xb <<= 16;
- *ya <<= 16; *yb <<= 16;
-
- diff = extents->x1 - dst->x1;
- if (diff > 0) {
- dst->x1 = extents->x1;
- *xa += (diff * xsw) / xdw;
- }
- diff = dst->x2 - extents->x2;
- if (diff > 0) {
- dst->x2 = extents->x2;
- *xb -= (diff * xsw) / xdw;
- }
- diff = extents->y1 - dst->y1;
- if (diff > 0) {
- dst->y1 = extents->y1;
- *ya += (diff * ysw) / ydw;
- }
- diff = dst->y2 - extents->y2;
- if (diff > 0) {
- dst->y2 = extents->y2;
- *yb -= (diff * ysw) / ydw;
- }
-
- if (*xa < 0) {
- diff = (((-*xa) * xdw) + xsw - 1) / xsw;
- dst->x1 += diff;
- *xa += (diff * xsw) / xdw;
- }
- delta = *xb - (width << 16);
- if (delta > 0) {
- diff = ((delta * xdw) + xsw - 1) / xsw;
- dst->x2 -= diff;
- *xb -= (diff * xsw) / xdw;
- }
- if (*xa >= *xb) return FALSE;
-
- if (*ya < 0) {
- diff = (((-*ya) * ydw) + ysw - 1) / ysw;
- dst->y1 += diff;
- *ya += (diff * ysw) / ydw;
- }
- delta = *yb - (height << 16);
- if (delta > 0) {
- diff = ((delta * ydw) + ysw - 1) / ysw;
- dst->y2 -= diff;
- *yb -= (diff * ysw) / ydw;
- }
- if (*ya >= *yb) return FALSE;
-
- if ((dst->x1 > extents->x1) || (dst->x2 < extents->x2) ||
- (dst->y1 > extents->y1) || (dst->y2 < extents->y2))
- {
- RegionRec clipReg;
- RegionInit(&clipReg, dst, 1);
- RegionIntersect(reg, reg, &clipReg);
- RegionUninit(&clipReg);
- }
- return TRUE;
-}
-
-void
-xf86XVCopyYUV12ToPacked(
- const void *srcy,
- const void *srcv,
- const void *srcu,
- void *dst,
- int srcPitchy,
- int srcPitchuv,
- int dstPitch,
- int h,
- int w
-){
- CARD32 *Dst;
- const CARD8 *Y, *U, *V;
- int i, j;
-
- w >>= 1;
-
- for (j = 0; j < h; j++) {
- Dst = dst;
- Y = srcy; V = srcv; U = srcu;
- i = w;
- while (i >= 4) {
-#if X_BYTE_ORDER == X_LITTLE_ENDIAN
- Dst[0] = Y[0] | (Y[1] << 16) | (U[0] << 8) | (V[0] << 24);
- Dst[1] = Y[2] | (Y[3] << 16) | (U[1] << 8) | (V[1] << 24);
- Dst[2] = Y[4] | (Y[5] << 16) | (U[2] << 8) | (V[2] << 24);
- Dst[3] = Y[6] | (Y[7] << 16) | (U[3] << 8) | (V[3] << 24);
-#else
- /* This assumes a little-endian framebuffer */
- Dst[0] = (Y[0] << 24) | (Y[1] << 8) | (U[0] << 16) | V[0];
- Dst[1] = (Y[2] << 24) | (Y[3] << 8) | (U[1] << 16) | V[1];
- Dst[2] = (Y[4] << 24) | (Y[5] << 8) | (U[2] << 16) | V[2];
- Dst[3] = (Y[6] << 24) | (Y[7] << 8) | (U[3] << 16) | V[3];
-#endif
- Dst += 4; Y += 8; V += 4; U += 4;
- i -= 4;
- }
-
- while (i--) {
-#if X_BYTE_ORDER == X_LITTLE_ENDIAN
- Dst[0] = Y[0] | (Y[1] << 16) | (U[0] << 8) | (V[0] << 24);
-#else
- /* This assumes a little-endian framebuffer */
- Dst[0] = (Y[0] << 24) | (Y[1] << 8) | (U[0] << 16) | V[0];
-#endif
- Dst++; Y += 2; V++; U++;
- }
-
- dst = (CARD8 *)dst + dstPitch;
- srcy = (const CARD8 *)srcy + srcPitchy;
- if (j & 1) {
- srcu = (const CARD8 *)srcu + srcPitchuv;
- srcv = (const CARD8 *)srcv + srcPitchuv;
- }
- }
-}
-
-void
-xf86XVCopyPacked(
- const void *src,
- void *dst,
- int srcPitch,
- int dstPitch,
- int h,
- int w
-){
- const CARD32 *Src;
- CARD32 *Dst;
- int i;
-
- w >>= 1;
- while (--h >= 0) {
- do {
- Dst = dst; Src = src;
- i = w;
- while (i >= 4) {
- Dst[0] = Src[0];
- Dst[1] = Src[1];
- Dst[2] = Src[2];
- Dst[3] = Src[3];
- Dst += 4; Src += 4; i -= 4;
- }
- if (!i) break;
- Dst[0] = Src[0];
- if (i == 1) break;
- Dst[1] = Src[1];
- if (i == 2) break;
- Dst[2] = Src[2];
- } while (0);
-
- src = (const CARD8 *)src + srcPitch;
- dst = (CARD8 *)dst + dstPitch;
- }
-}
+/* + * XFree86 Xv DDX written by Mark Vojkovich (markv@valinux.com) + */ +/* + * Copyright (c) 1998-2003 by The XFree86 Project, Inc. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) 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. + * + * Except as contained in this notice, the name of the copyright holder(s) + * and author(s) shall not be used in advertising or otherwise to promote + * the sale, use or other dealings in this Software without prior written + * authorization from the copyright holder(s) and author(s). + */ + + +#ifdef HAVE_XORG_CONFIG_H +#include <xorg-config.h> +#endif + +#include "misc.h" +#include "xf86.h" +#include "xf86_OSproc.h" + +#include <X11/X.h> +#include <X11/Xproto.h> +#include "scrnintstr.h" +#include "regionstr.h" +#include "windowstr.h" +#include "pixmapstr.h" +#include "mivalidate.h" +#include "validate.h" +#include "resource.h" +#include "gcstruct.h" +#include "dixstruct.h" + +#include <X11/extensions/Xv.h> +#include <X11/extensions/Xvproto.h> +#include "xvdix.h" +#include "xvmodproc.h" + +#include "xf86xvpriv.h" + + +/* XvScreenRec fields */ + +static Bool xf86XVCloseScreen(int, ScreenPtr); +static int xf86XVQueryAdaptors(ScreenPtr, XvAdaptorPtr *, int *); + +/* XvAdaptorRec fields */ + +static int xf86XVAllocatePort(unsigned long, XvPortPtr, XvPortPtr*); +static int xf86XVFreePort(XvPortPtr); +static int xf86XVPutVideo(ClientPtr, DrawablePtr,XvPortPtr, GCPtr, + INT16, INT16, CARD16, CARD16, + INT16, INT16, CARD16, CARD16); +static int xf86XVPutStill(ClientPtr, DrawablePtr,XvPortPtr, GCPtr, + INT16, INT16, CARD16, CARD16, + INT16, INT16, CARD16, CARD16); +static int xf86XVGetVideo(ClientPtr, DrawablePtr,XvPortPtr, GCPtr, + INT16, INT16, CARD16, CARD16, + INT16, INT16, CARD16, CARD16); +static int xf86XVGetStill(ClientPtr, DrawablePtr,XvPortPtr, GCPtr, + INT16, INT16, CARD16, CARD16, + INT16, INT16, CARD16, CARD16); +static int xf86XVStopVideo(ClientPtr, XvPortPtr, DrawablePtr); +static int xf86XVSetPortAttribute(ClientPtr, XvPortPtr, Atom, INT32); +static int xf86XVGetPortAttribute(ClientPtr, XvPortPtr, Atom, INT32*); +static int xf86XVQueryBestSize(ClientPtr, XvPortPtr, CARD8, + CARD16, CARD16,CARD16, CARD16, + unsigned int*, unsigned int*); +static int xf86XVPutImage(ClientPtr, DrawablePtr, XvPortPtr, GCPtr, + INT16, INT16, CARD16, CARD16, + INT16, INT16, CARD16, CARD16, + XvImagePtr, unsigned char*, Bool, + CARD16, CARD16); +static int xf86XVQueryImageAttributes(ClientPtr, XvPortPtr, XvImagePtr, + CARD16*, CARD16*, int*, int*); + + +/* ScreenRec fields */ + +static Bool xf86XVDestroyWindow(WindowPtr pWin); +static void xf86XVWindowExposures(WindowPtr pWin, RegionPtr r1, RegionPtr r2); +static void xf86XVPostValidateTree(WindowPtr pWin, WindowPtr pLayerWin, VTKind kind); +static void xf86XVClipNotify(WindowPtr pWin, int dx, int dy); + +#define PostValidateTreeUndefined ((PostValidateTreeProcPtr)-1) + +/* ScrnInfoRec functions */ + +static Bool xf86XVEnterVT(int, int); +static void xf86XVLeaveVT(int, int); +static void xf86XVAdjustFrame(int index, int x, int y, int flags); +static void xf86XVModeSet(ScrnInfoPtr pScrn); + +/* misc */ + +static Bool xf86XVInitAdaptors(ScreenPtr, XF86VideoAdaptorPtr*, int); + + +static DevPrivateKeyRec XF86XVWindowKeyRec; +#define XF86XVWindowKey (&XF86XVWindowKeyRec) + +DevPrivateKey XF86XvScreenKey; + +static unsigned long PortResource = 0; + +DevPrivateKey (*XvGetScreenKeyProc)(void) = NULL; +unsigned long (*XvGetRTPortProc)(void) = NULL; +int (*XvScreenInitProc)(ScreenPtr) = NULL; + +#define GET_XV_SCREEN(pScreen) \ + ((XvScreenPtr)dixLookupPrivate(&(pScreen)->devPrivates, XF86XvScreenKey)) + +#define GET_XF86XV_SCREEN(pScreen) \ + ((XF86XVScreenPtr)(GET_XV_SCREEN(pScreen)->devPriv.ptr)) + +#define GET_XF86XV_WINDOW(pWin) \ + ((XF86XVWindowPtr)dixLookupPrivate(&(pWin)->devPrivates, XF86XVWindowKey)) + +static xf86XVInitGenericAdaptorPtr *GenDrivers = NULL; +static int NumGenDrivers = 0; + +int +xf86XVRegisterGenericAdaptorDriver( + xf86XVInitGenericAdaptorPtr InitFunc +){ + xf86XVInitGenericAdaptorPtr *newdrivers; + + newdrivers = realloc(GenDrivers, sizeof(xf86XVInitGenericAdaptorPtr) * + (1 + NumGenDrivers)); + if (!newdrivers) + return 0; + GenDrivers = newdrivers; + + GenDrivers[NumGenDrivers++] = InitFunc; + + return 1; +} + +int +xf86XVListGenericAdaptors( + ScrnInfoPtr pScrn, + XF86VideoAdaptorPtr **adaptors +){ + int i,j,n,num; + XF86VideoAdaptorPtr *DrivAdap,*new; + + num = 0; + *adaptors = NULL; + /* + * The v4l driver registers itself first, but can use surfaces registered + * by other drivers. So, call the v4l driver last. + */ + for (i = NumGenDrivers; --i >= 0; ) { + DrivAdap = NULL; + n = (*GenDrivers[i])(pScrn, &DrivAdap); + if (0 == n) + continue; + new = realloc(*adaptors, sizeof(XF86VideoAdaptorPtr) * (num+n)); + if (NULL == new) + continue; + *adaptors = new; + for (j = 0; j < n; j++, num++) + (*adaptors)[num] = DrivAdap[j]; + } + return num; +} + + +/**************** Offscreen surface stuff *******************/ + +typedef struct { + XF86OffscreenImagePtr images; + int num; +} OffscreenImageRec; + +static DevPrivateKeyRec OffscreenPrivateKeyRec; +#define OffscreenPrivateKey (&OffscreenPrivateKeyRec) +#define GetOffscreenImage(pScreen) ((OffscreenImageRec *) dixLookupPrivate(&(pScreen)->devPrivates, OffscreenPrivateKey)) + +Bool +xf86XVRegisterOffscreenImages( + ScreenPtr pScreen, + XF86OffscreenImagePtr images, + int num +){ + OffscreenImageRec *OffscreenImage; + /* This function may be called before xf86XVScreenInit, so there's + * no better place than this to call dixRegisterPrivateKey to ensure we + * have space reserved. After the first call it is a no-op. */ + if(!dixRegisterPrivateKey(OffscreenPrivateKey, PRIVATE_SCREEN, sizeof(OffscreenImageRec)) || + !(OffscreenImage = GetOffscreenImage(pScreen))) + /* Every X.org driver assumes this function always succeeds, so + * just die on allocation failure. */ + FatalError("Could not allocate private storage for XV offscreen images.\n"); + + OffscreenImage->num = num; + OffscreenImage->images = images; + return TRUE; +} + +XF86OffscreenImagePtr +xf86XVQueryOffscreenImages( + ScreenPtr pScreen, + int *num +){ + OffscreenImageRec *OffscreenImage = GetOffscreenImage(pScreen); + *num = OffscreenImage->num; + return OffscreenImage->images; +} + + +XF86VideoAdaptorPtr +xf86XVAllocateVideoAdaptorRec(ScrnInfoPtr pScrn) +{ + return calloc(1, sizeof(XF86VideoAdaptorRec)); +} + +void +xf86XVFreeVideoAdaptorRec(XF86VideoAdaptorPtr ptr) +{ + free(ptr); +} + + +Bool +xf86XVScreenInit( + ScreenPtr pScreen, + XF86VideoAdaptorPtr *adaptors, + int num +){ + ScrnInfoPtr pScrn; + XF86XVScreenPtr ScreenPriv; + XvScreenPtr pxvs; + + if(num <= 0 || + !XvGetScreenKeyProc || !XvGetRTPortProc || !XvScreenInitProc) + return FALSE; + + if(Success != (*XvScreenInitProc)(pScreen)) return FALSE; + + if (!dixRegisterPrivateKey(&XF86XVWindowKeyRec, PRIVATE_WINDOW, 0)) + return FALSE; + + XF86XvScreenKey = (*XvGetScreenKeyProc)(); + + PortResource = (*XvGetRTPortProc)(); + + pxvs = GET_XV_SCREEN(pScreen); + + /* Anyone initializing the Xv layer must provide these two. + The Xv di layer calls them without even checking if they exist! */ + + pxvs->ddCloseScreen = xf86XVCloseScreen; + pxvs->ddQueryAdaptors = xf86XVQueryAdaptors; + + /* The Xv di layer provides us with a private hook so that we don't + have to allocate our own screen private. They also provide + a CloseScreen hook so that we don't have to wrap it. I'm not + sure that I appreciate that. */ + + ScreenPriv = malloc(sizeof(XF86XVScreenRec)); + pxvs->devPriv.ptr = (pointer)ScreenPriv; + + if(!ScreenPriv) return FALSE; + + pScrn = xf86Screens[pScreen->myNum]; + + ScreenPriv->DestroyWindow = pScreen->DestroyWindow; + ScreenPriv->WindowExposures = pScreen->WindowExposures; + ScreenPriv->PostValidateTree = PostValidateTreeUndefined; + ScreenPriv->ClipNotify = pScreen->ClipNotify; + ScreenPriv->EnterVT = pScrn->EnterVT; + ScreenPriv->LeaveVT = pScrn->LeaveVT; + ScreenPriv->AdjustFrame = pScrn->AdjustFrame; + ScreenPriv->ModeSet = pScrn->ModeSet; + + pScreen->DestroyWindow = xf86XVDestroyWindow; + pScreen->WindowExposures = xf86XVWindowExposures; + pScreen->ClipNotify = xf86XVClipNotify; + pScrn->EnterVT = xf86XVEnterVT; + pScrn->LeaveVT = xf86XVLeaveVT; + if(pScrn->AdjustFrame) + pScrn->AdjustFrame = xf86XVAdjustFrame; + pScrn->ModeSet = xf86XVModeSet; + + if(!xf86XVInitAdaptors(pScreen, adaptors, num)) + return FALSE; + + return TRUE; +} + +static void +xf86XVFreeAdaptor(XvAdaptorPtr pAdaptor) +{ + int i; + + free(pAdaptor->name); + pAdaptor->name = NULL; + + if(pAdaptor->pEncodings) { + XvEncodingPtr pEncode = pAdaptor->pEncodings; + + for(i = 0; i < pAdaptor->nEncodings; i++, pEncode++) + free(pEncode->name); + free(pAdaptor->pEncodings); + pAdaptor->pEncodings = NULL; + } + + free(pAdaptor->pFormats); + pAdaptor->pFormats = NULL; + + if(pAdaptor->pPorts) { + XvPortPtr pPort = pAdaptor->pPorts; + XvPortRecPrivatePtr pPriv; + + for(i = 0; i < pAdaptor->nPorts; i++, pPort++) { + pPriv = (XvPortRecPrivatePtr)pPort->devPriv.ptr; + if(pPriv) { + if(pPriv->clientClip) + RegionDestroy(pPriv->clientClip); + if(pPriv->pCompositeClip && pPriv->FreeCompositeClip) + RegionDestroy(pPriv->pCompositeClip); + if (pPriv->ckeyFilled) + RegionDestroy(pPriv->ckeyFilled); + free(pPriv); + } + } + free(pAdaptor->pPorts); + pAdaptor->pPorts = NULL; + } + + if(pAdaptor->pAttributes) { + XvAttributePtr pAttribute = pAdaptor->pAttributes; + + for(i = 0; i < pAdaptor->nAttributes; i++, pAttribute++) + free(pAttribute->name); + free(pAdaptor->pAttributes); + pAdaptor->pAttributes = NULL; + } + + free(pAdaptor->pImages); + free(pAdaptor->devPriv.ptr); + pAdaptor->pImages = NULL; + pAdaptor->devPriv.ptr = NULL; +} + +static Bool +xf86XVInitAdaptors( + ScreenPtr pScreen, + XF86VideoAdaptorPtr *infoPtr, + int number +) { + XvScreenPtr pxvs = GET_XV_SCREEN(pScreen); + ScrnInfoPtr pScrn = xf86Screens[pScreen->myNum]; + XF86VideoAdaptorPtr adaptorPtr; + XvAdaptorPtr pAdaptor, pa; + XvAdaptorRecPrivatePtr adaptorPriv; + int na, numAdaptor; + XvPortRecPrivatePtr portPriv; + XvPortPtr pPort, pp; + int numPort; + XF86AttributePtr attributePtr; + XvAttributePtr pAttribute, pat; + XF86VideoFormatPtr formatPtr; + XvFormatPtr pFormat, pf; + int numFormat, totFormat; + XF86VideoEncodingPtr encodingPtr; + XvEncodingPtr pEncode, pe; + XF86ImagePtr imagePtr; + XvImagePtr pImage, pi; + int numVisuals; + VisualPtr pVisual; + int i; + + pxvs->nAdaptors = 0; + pxvs->pAdaptors = NULL; + + if(!(pAdaptor = calloc(number, sizeof(XvAdaptorRec)))) + return FALSE; + + for(pa = pAdaptor, na = 0, numAdaptor = 0; na < number; na++, adaptorPtr++) { + adaptorPtr = infoPtr[na]; + + if(!adaptorPtr->StopVideo || !adaptorPtr->SetPortAttribute || + !adaptorPtr->GetPortAttribute || !adaptorPtr->QueryBestSize) + continue; + + /* client libs expect at least one encoding */ + if(!adaptorPtr->nEncodings || !adaptorPtr->pEncodings) + continue; + + pa->type = adaptorPtr->type; + + if(!adaptorPtr->PutVideo && !adaptorPtr->GetVideo) + pa->type &= ~XvVideoMask; + + if(!adaptorPtr->PutStill && !adaptorPtr->GetStill) + pa->type &= ~XvStillMask; + + if(!adaptorPtr->PutImage || !adaptorPtr->QueryImageAttributes) + pa->type &= ~XvImageMask; + + if(!adaptorPtr->PutVideo && !adaptorPtr->PutImage && + !adaptorPtr->PutStill) + pa->type &= ~XvInputMask; + + if(!adaptorPtr->GetVideo && !adaptorPtr->GetStill) + pa->type &= ~XvOutputMask; + + if(!(adaptorPtr->type & (XvPixmapMask | XvWindowMask))) + continue; + if(!(adaptorPtr->type & (XvImageMask | XvVideoMask | XvStillMask))) + continue; + + pa->pScreen = pScreen; + pa->ddAllocatePort = xf86XVAllocatePort; + pa->ddFreePort = xf86XVFreePort; + pa->ddPutVideo = xf86XVPutVideo; + pa->ddPutStill = xf86XVPutStill; + pa->ddGetVideo = xf86XVGetVideo; + pa->ddGetStill = xf86XVGetStill; + pa->ddStopVideo = xf86XVStopVideo; + pa->ddPutImage = xf86XVPutImage; + pa->ddSetPortAttribute = xf86XVSetPortAttribute; + pa->ddGetPortAttribute = xf86XVGetPortAttribute; + pa->ddQueryBestSize = xf86XVQueryBestSize; + pa->ddQueryImageAttributes = xf86XVQueryImageAttributes; + pa->name = strdup(adaptorPtr->name); + + if(adaptorPtr->nEncodings && + (pEncode = calloc(adaptorPtr->nEncodings, sizeof(XvEncodingRec)))) { + + for(pe = pEncode, encodingPtr = adaptorPtr->pEncodings, i = 0; + i < adaptorPtr->nEncodings; pe++, i++, encodingPtr++) + { + pe->id = encodingPtr->id; + pe->pScreen = pScreen; + pe->name = strdup(encodingPtr->name); + pe->width = encodingPtr->width; + pe->height = encodingPtr->height; + pe->rate.numerator = encodingPtr->rate.numerator; + pe->rate.denominator = encodingPtr->rate.denominator; + } + pa->nEncodings = adaptorPtr->nEncodings; + pa->pEncodings = pEncode; + } + + if(adaptorPtr->nImages && + (pImage = calloc(adaptorPtr->nImages, sizeof(XvImageRec)))) { + + for(i = 0, pi = pImage, imagePtr = adaptorPtr->pImages; + i < adaptorPtr->nImages; i++, pi++, imagePtr++) + { + pi->id = imagePtr->id; + pi->type = imagePtr->type; + pi->byte_order = imagePtr->byte_order; + memcpy(pi->guid, imagePtr->guid, 16); + pi->bits_per_pixel = imagePtr->bits_per_pixel; + pi->format = imagePtr->format; + pi->num_planes = imagePtr->num_planes; + pi->depth = imagePtr->depth; + pi->red_mask = imagePtr->red_mask; + pi->green_mask = imagePtr->green_mask; + pi->blue_mask = imagePtr->blue_mask; + pi->y_sample_bits = imagePtr->y_sample_bits; + pi->u_sample_bits = imagePtr->u_sample_bits; + pi->v_sample_bits = imagePtr->v_sample_bits; + pi->horz_y_period = imagePtr->horz_y_period; + pi->horz_u_period = imagePtr->horz_u_period; + pi->horz_v_period = imagePtr->horz_v_period; + pi->vert_y_period = imagePtr->vert_y_period; + pi->vert_u_period = imagePtr->vert_u_period; + pi->vert_v_period = imagePtr->vert_v_period; + memcpy(pi->component_order, imagePtr->component_order, 32); + pi->scanline_order = imagePtr->scanline_order; + } + pa->nImages = adaptorPtr->nImages; + pa->pImages = pImage; + } + + if(adaptorPtr->nAttributes && + (pAttribute = calloc(adaptorPtr->nAttributes, sizeof(XvAttributeRec)))) + { + for(pat = pAttribute, attributePtr = adaptorPtr->pAttributes, i = 0; + i < adaptorPtr->nAttributes; pat++, i++, attributePtr++) + { + pat->flags = attributePtr->flags; + pat->min_value = attributePtr->min_value; + pat->max_value = attributePtr->max_value; + pat->name = strdup(attributePtr->name); + } + pa->nAttributes = adaptorPtr->nAttributes; + pa->pAttributes = pAttribute; + } + + + totFormat = adaptorPtr->nFormats; + + if(!(pFormat = calloc(totFormat, sizeof(XvFormatRec)))) { + xf86XVFreeAdaptor(pa); + continue; + } + for(pf = pFormat, i = 0, numFormat = 0, formatPtr = adaptorPtr->pFormats; + i < adaptorPtr->nFormats; i++, formatPtr++) + { + numVisuals = pScreen->numVisuals; + pVisual = pScreen->visuals; + + while(numVisuals--) { + if((pVisual->class == formatPtr->class) && + (pVisual->nplanes == formatPtr->depth)) { + + if(numFormat >= totFormat) { + void *moreSpace; + totFormat *= 2; + moreSpace = realloc(pFormat, + totFormat * sizeof(XvFormatRec)); + if(!moreSpace) break; + pFormat = moreSpace; + pf = pFormat + numFormat; + } + + pf->visual = pVisual->vid; + pf->depth = formatPtr->depth; + + pf++; + numFormat++; + } + pVisual++; + } + } + pa->nFormats = numFormat; + pa->pFormats = pFormat; + if(!numFormat) { + xf86XVFreeAdaptor(pa); + continue; + } + + if(!(adaptorPriv = calloc(1, sizeof(XvAdaptorRecPrivate)))) { + xf86XVFreeAdaptor(pa); + continue; + } + + adaptorPriv->flags = adaptorPtr->flags; + adaptorPriv->PutVideo = adaptorPtr->PutVideo; + adaptorPriv->PutStill = adaptorPtr->PutStill; + adaptorPriv->GetVideo = adaptorPtr->GetVideo; + adaptorPriv->GetStill = adaptorPtr->GetStill; + adaptorPriv->StopVideo = adaptorPtr->StopVideo; + adaptorPriv->SetPortAttribute = adaptorPtr->SetPortAttribute; + adaptorPriv->GetPortAttribute = adaptorPtr->GetPortAttribute; + adaptorPriv->QueryBestSize = adaptorPtr->QueryBestSize; + adaptorPriv->QueryImageAttributes = adaptorPtr->QueryImageAttributes; + adaptorPriv->PutImage = adaptorPtr->PutImage; + adaptorPriv->ReputImage = adaptorPtr->ReputImage; /* image/still */ + + pa->devPriv.ptr = (pointer)adaptorPriv; + + if(!(pPort = calloc(adaptorPtr->nPorts, sizeof(XvPortRec)))) { + xf86XVFreeAdaptor(pa); + continue; + } + for(pp = pPort, i = 0, numPort = 0; + i < adaptorPtr->nPorts; i++) { + + if(!(pp->id = FakeClientID(0))) + continue; + + if(!(portPriv = calloc(1, sizeof(XvPortRecPrivate)))) + continue; + + if(!AddResource(pp->id, PortResource, pp)) { + free(portPriv); + continue; + } + + pp->pAdaptor = pa; + pp->pNotify = (XvPortNotifyPtr)NULL; + pp->pDraw = (DrawablePtr)NULL; + pp->client = (ClientPtr)NULL; + pp->grab.client = (ClientPtr)NULL; + pp->time = currentTime; + pp->devPriv.ptr = portPriv; + + portPriv->pScrn = pScrn; + portPriv->AdaptorRec = adaptorPriv; + portPriv->DevPriv.ptr = adaptorPtr->pPortPrivates[i].ptr; + + pp++; + numPort++; + } + pa->nPorts = numPort; + pa->pPorts = pPort; + if(!numPort) { + xf86XVFreeAdaptor(pa); + continue; + } + + pa->base_id = pPort->id; + + pa++; + numAdaptor++; + } + + if(numAdaptor) { + pxvs->nAdaptors = numAdaptor; + pxvs->pAdaptors = pAdaptor; + } else { + free(pAdaptor); + return FALSE; + } + + return TRUE; +} + +/* Video should be clipped to the intersection of the window cliplist + and the client cliplist specified in the GC for which the video was + initialized. When we need to reclip a window, the GC that started + the video may not even be around anymore. That's why we save the + client clip from the GC when the video is initialized. We then + use xf86XVUpdateCompositeClip to calculate the new composite clip + when we need it. This is different from what DEC did. They saved + the GC and used it's clip list when they needed to reclip the window, + even if the client clip was different from the one the video was + initialized with. If the original GC was destroyed, they had to stop + the video. I like the new method better (MArk). + + This function only works for windows. Will need to rewrite when + (if) we support pixmap rendering. +*/ + +static void +xf86XVUpdateCompositeClip(XvPortRecPrivatePtr portPriv) +{ + RegionPtr pregWin, pCompositeClip; + WindowPtr pWin; + Bool freeCompClip = FALSE; + + if(portPriv->pCompositeClip) + return; + + pWin = (WindowPtr)portPriv->pDraw; + + /* get window clip list */ + if(portPriv->subWindowMode == IncludeInferiors) { + pregWin = NotClippedByChildren(pWin); + freeCompClip = TRUE; + } else + pregWin = &pWin->clipList; + + if(!portPriv->clientClip) { + portPriv->pCompositeClip = pregWin; + portPriv->FreeCompositeClip = freeCompClip; + return; + } + + pCompositeClip = RegionCreate(NullBox, 1); + RegionCopy(pCompositeClip, portPriv->clientClip); + RegionTranslate(pCompositeClip, + portPriv->pDraw->x, portPriv->pDraw->y); + RegionIntersect(pCompositeClip, pregWin, pCompositeClip); + + portPriv->pCompositeClip = pCompositeClip; + portPriv->FreeCompositeClip = TRUE; + + if(freeCompClip) { + RegionDestroy(pregWin); + } +} + +/* Save the current clientClip and update the CompositeClip whenever + we have a fresh GC */ + +static void +xf86XVCopyClip( + XvPortRecPrivatePtr portPriv, + GCPtr pGC +){ + /* copy the new clip if it exists */ + if((pGC->clientClipType == CT_REGION) && pGC->clientClip) { + if(!portPriv->clientClip) + portPriv->clientClip = RegionCreate(NullBox, 1); + /* Note: this is in window coordinates */ + RegionCopy(portPriv->clientClip, pGC->clientClip); + RegionTranslate(portPriv->clientClip, + pGC->clipOrg.x, pGC->clipOrg.y); + } else if(portPriv->clientClip) { /* free the old clientClip */ + RegionDestroy(portPriv->clientClip); + portPriv->clientClip = NULL; + } + + /* get rid of the old clip list */ + if(portPriv->pCompositeClip && portPriv->FreeCompositeClip) { + RegionDestroy(portPriv->pCompositeClip); + } + + portPriv->pCompositeClip = pGC->pCompositeClip; + portPriv->FreeCompositeClip = FALSE; + portPriv->subWindowMode = pGC->subWindowMode; +} + +static void +xf86XVCopyCompositeClip(XvPortRecPrivatePtr portPriv, + GCPtr pGC, + DrawablePtr pDraw) +{ + if (!portPriv->clientClip) + portPriv->clientClip = RegionCreate(NullBox, 1); + /* Keep the original GC composite clip around for ReputImage */ + RegionCopy(portPriv->clientClip, pGC->pCompositeClip); + RegionTranslate(portPriv->clientClip, + -pDraw->x, -pDraw->y); + + /* get rid of the old clip list */ + if (portPriv->pCompositeClip && portPriv->FreeCompositeClip) + RegionDestroy(portPriv->pCompositeClip); + + portPriv->pCompositeClip = pGC->pCompositeClip; + portPriv->FreeCompositeClip = FALSE; + portPriv->subWindowMode = pGC->subWindowMode; +} + +static int +xf86XVRegetVideo(XvPortRecPrivatePtr portPriv) +{ + RegionRec WinRegion; + RegionRec ClipRegion; + BoxRec WinBox; + int ret = Success; + Bool clippedAway = FALSE; + + xf86XVUpdateCompositeClip(portPriv); + + /* translate the video region to the screen */ + WinBox.x1 = portPriv->pDraw->x + portPriv->drw_x; + WinBox.y1 = portPriv->pDraw->y + portPriv->drw_y; + WinBox.x2 = WinBox.x1 + portPriv->drw_w; + WinBox.y2 = WinBox.y1 + portPriv->drw_h; + + /* clip to the window composite clip */ + RegionInit(&WinRegion, &WinBox, 1); + RegionNull(&ClipRegion); + RegionIntersect(&ClipRegion, &WinRegion, portPriv->pCompositeClip); + + /* that's all if it's totally obscured */ + if(!RegionNotEmpty(&ClipRegion)) { + clippedAway = TRUE; + goto CLIP_VIDEO_BAILOUT; + } + + if(portPriv->AdaptorRec->flags & VIDEO_INVERT_CLIPLIST) { + RegionSubtract(&ClipRegion, &WinRegion, &ClipRegion); + } + + ret = (*portPriv->AdaptorRec->GetVideo)(portPriv->pScrn, + portPriv->vid_x, portPriv->vid_y, + WinBox.x1, WinBox.y1, + portPriv->vid_w, portPriv->vid_h, + portPriv->drw_w, portPriv->drw_h, + &ClipRegion, portPriv->DevPriv.ptr, + portPriv->pDraw); + + if(ret == Success) + portPriv->isOn = XV_ON; + +CLIP_VIDEO_BAILOUT: + + if((clippedAway || (ret != Success)) && portPriv->isOn == XV_ON) { + (*portPriv->AdaptorRec->StopVideo)( + portPriv->pScrn, portPriv->DevPriv.ptr, FALSE); + portPriv->isOn = XV_PENDING; + } + + /* This clip was copied and only good for one shot */ + if(!portPriv->FreeCompositeClip) + portPriv->pCompositeClip = NULL; + + RegionUninit(&WinRegion); + RegionUninit(&ClipRegion); + + return ret; +} + + +static int +xf86XVReputVideo(XvPortRecPrivatePtr portPriv) +{ + RegionRec WinRegion; + RegionRec ClipRegion; + BoxRec WinBox; + int ret = Success; + Bool clippedAway = FALSE; + + xf86XVUpdateCompositeClip(portPriv); + + /* translate the video region to the screen */ + WinBox.x1 = portPriv->pDraw->x + portPriv->drw_x; + WinBox.y1 = portPriv->pDraw->y + portPriv->drw_y; + WinBox.x2 = WinBox.x1 + portPriv->drw_w; + WinBox.y2 = WinBox.y1 + portPriv->drw_h; + + /* clip to the window composite clip */ + RegionInit(&WinRegion, &WinBox, 1); + RegionNull(&ClipRegion); + RegionIntersect(&ClipRegion, &WinRegion, portPriv->pCompositeClip); + + /* clip and translate to the viewport */ + if(portPriv->AdaptorRec->flags & VIDEO_CLIP_TO_VIEWPORT) { + RegionRec VPReg; + BoxRec VPBox; + + VPBox.x1 = portPriv->pScrn->frameX0; + VPBox.y1 = portPriv->pScrn->frameY0; + VPBox.x2 = portPriv->pScrn->frameX1 + 1; + VPBox.y2 = portPriv->pScrn->frameY1 + 1; + + RegionInit(&VPReg, &VPBox, 1); + RegionIntersect(&ClipRegion, &ClipRegion, &VPReg); + RegionUninit(&VPReg); + } + + /* that's all if it's totally obscured */ + if(!RegionNotEmpty(&ClipRegion)) { + clippedAway = TRUE; + goto CLIP_VIDEO_BAILOUT; + } + + /* bailout if we have to clip but the hardware doesn't support it */ + if(portPriv->AdaptorRec->flags & VIDEO_NO_CLIPPING) { + BoxPtr clipBox = RegionRects(&ClipRegion); + if( (RegionNumRects(&ClipRegion) != 1) || + (clipBox->x1 != WinBox.x1) || (clipBox->x2 != WinBox.x2) || + (clipBox->y1 != WinBox.y1) || (clipBox->y2 != WinBox.y2)) + { + clippedAway = TRUE; + goto CLIP_VIDEO_BAILOUT; + } + } + + if(portPriv->AdaptorRec->flags & VIDEO_INVERT_CLIPLIST) { + RegionSubtract(&ClipRegion, &WinRegion, &ClipRegion); + } + + ret = (*portPriv->AdaptorRec->PutVideo)(portPriv->pScrn, + portPriv->vid_x, portPriv->vid_y, + WinBox.x1, WinBox.y1, + portPriv->vid_w, portPriv->vid_h, + portPriv->drw_w, portPriv->drw_h, + &ClipRegion, portPriv->DevPriv.ptr, + portPriv->pDraw); + + if(ret == Success) portPriv->isOn = XV_ON; + +CLIP_VIDEO_BAILOUT: + + if((clippedAway || (ret != Success)) && (portPriv->isOn == XV_ON)) { + (*portPriv->AdaptorRec->StopVideo)( + portPriv->pScrn, portPriv->DevPriv.ptr, FALSE); + portPriv->isOn = XV_PENDING; + } + + /* This clip was copied and only good for one shot */ + if(!portPriv->FreeCompositeClip) + portPriv->pCompositeClip = NULL; + + RegionUninit(&WinRegion); + RegionUninit(&ClipRegion); + + return ret; +} + +/* Reput image/still */ +static int +xf86XVReputImage(XvPortRecPrivatePtr portPriv) +{ + RegionRec WinRegion; + RegionRec ClipRegion; + BoxRec WinBox; + int ret = Success; + Bool clippedAway = FALSE; + + xf86XVUpdateCompositeClip(portPriv); + + /* the clip can get smaller over time */ + RegionCopy(portPriv->clientClip, portPriv->pCompositeClip); + RegionTranslate(portPriv->clientClip, + -portPriv->pDraw->x, -portPriv->pDraw->y); + + /* translate the video region to the screen */ + WinBox.x1 = portPriv->pDraw->x + portPriv->drw_x; + WinBox.y1 = portPriv->pDraw->y + portPriv->drw_y; + WinBox.x2 = WinBox.x1 + portPriv->drw_w; + WinBox.y2 = WinBox.y1 + portPriv->drw_h; + + /* clip to the window composite clip */ + RegionInit(&WinRegion, &WinBox, 1); + RegionNull(&ClipRegion); + RegionIntersect(&ClipRegion, &WinRegion, portPriv->pCompositeClip); + + /* clip and translate to the viewport */ + if(portPriv->AdaptorRec->flags & VIDEO_CLIP_TO_VIEWPORT) { + RegionRec VPReg; + BoxRec VPBox; + + VPBox.x1 = portPriv->pScrn->frameX0; + VPBox.y1 = portPriv->pScrn->frameY0; + VPBox.x2 = portPriv->pScrn->frameX1 + 1; + VPBox.y2 = portPriv->pScrn->frameY1 + 1; + + RegionInit(&VPReg, &VPBox, 1); + RegionIntersect(&ClipRegion, &ClipRegion, &VPReg); + RegionUninit(&VPReg); + } + + /* that's all if it's totally obscured */ + if(!RegionNotEmpty(&ClipRegion)) { + clippedAway = TRUE; + goto CLIP_VIDEO_BAILOUT; + } + + /* bailout if we have to clip but the hardware doesn't support it */ + if(portPriv->AdaptorRec->flags & VIDEO_NO_CLIPPING) { + BoxPtr clipBox = RegionRects(&ClipRegion); + if( (RegionNumRects(&ClipRegion) != 1) || + (clipBox->x1 != WinBox.x1) || (clipBox->x2 != WinBox.x2) || + (clipBox->y1 != WinBox.y1) || (clipBox->y2 != WinBox.y2)) + { + clippedAway = TRUE; + goto CLIP_VIDEO_BAILOUT; + } + } + + if(portPriv->AdaptorRec->flags & VIDEO_INVERT_CLIPLIST) { + RegionSubtract(&ClipRegion, &WinRegion, &ClipRegion); + } + + ret = (*portPriv->AdaptorRec->ReputImage)(portPriv->pScrn, + portPriv->vid_x, portPriv->vid_y, + WinBox.x1, WinBox.y1, + portPriv->vid_w, portPriv->vid_h, + portPriv->drw_w, portPriv->drw_h, + &ClipRegion, portPriv->DevPriv.ptr, + portPriv->pDraw); + + portPriv->isOn = (ret == Success) ? XV_ON : XV_OFF; + +CLIP_VIDEO_BAILOUT: + + if((clippedAway || (ret != Success)) && (portPriv->isOn == XV_ON)) { + (*portPriv->AdaptorRec->StopVideo)( + portPriv->pScrn, portPriv->DevPriv.ptr, FALSE); + portPriv->isOn = XV_PENDING; + } + + /* This clip was copied and only good for one shot */ + if(!portPriv->FreeCompositeClip) + portPriv->pCompositeClip = NULL; + + RegionUninit(&WinRegion); + RegionUninit(&ClipRegion); + + return ret; +} + + +static int +xf86XVReputAllVideo(WindowPtr pWin, pointer data) +{ + XF86XVWindowPtr WinPriv = GET_XF86XV_WINDOW(pWin); + + while(WinPriv) { + if(WinPriv->PortRec->type == XvInputMask) + xf86XVReputVideo(WinPriv->PortRec); + else + xf86XVRegetVideo(WinPriv->PortRec); + WinPriv = WinPriv->next; + } + + return WT_WALKCHILDREN; +} + +static int +xf86XVEnlistPortInWindow(WindowPtr pWin, XvPortRecPrivatePtr portPriv) +{ + XF86XVWindowPtr winPriv, PrivRoot; + + winPriv = PrivRoot = GET_XF86XV_WINDOW(pWin); + + /* Enlist our port in the window private */ + while(winPriv) { + if(winPriv->PortRec == portPriv) /* we're already listed */ + break; + winPriv = winPriv->next; + } + + if(!winPriv) { + winPriv = calloc(1, sizeof(XF86XVWindowRec)); + if(!winPriv) return BadAlloc; + winPriv->PortRec = portPriv; + winPriv->next = PrivRoot; + dixSetPrivate(&pWin->devPrivates, XF86XVWindowKey, winPriv); + } + + portPriv->pDraw = (DrawablePtr)pWin; + + return Success; +} + + +static void +xf86XVRemovePortFromWindow(WindowPtr pWin, XvPortRecPrivatePtr portPriv) +{ + XF86XVWindowPtr winPriv, prevPriv = NULL; + winPriv = GET_XF86XV_WINDOW(pWin); + + while(winPriv) { + if(winPriv->PortRec == portPriv) { + if(prevPriv) + prevPriv->next = winPriv->next; + else + dixSetPrivate(&pWin->devPrivates, XF86XVWindowKey, + winPriv->next); + free(winPriv); + break; + } + prevPriv = winPriv; + winPriv = winPriv->next; + } + portPriv->pDraw = NULL; + if (portPriv->ckeyFilled) { + RegionDestroy(portPriv->ckeyFilled); + portPriv->ckeyFilled = NULL; + } + portPriv->clipChanged = FALSE; +} + +static void +xf86XVReputOrStopPort(XvPortRecPrivatePtr pPriv, + WindowPtr pWin, + Bool visible) +{ + if (!visible) { + if (pPriv->isOn == XV_ON) { + (*pPriv->AdaptorRec->StopVideo)(pPriv->pScrn, pPriv->DevPriv.ptr, FALSE); + pPriv->isOn = XV_PENDING; + } + + if (!pPriv->type) /* overlaid still/image*/ + xf86XVRemovePortFromWindow(pWin, pPriv); + + return; + } + + switch (pPriv->type) { + case XvInputMask: + xf86XVReputVideo(pPriv); + break; + case XvOutputMask: + xf86XVRegetVideo(pPriv); + break; + default: /* overlaid still/image*/ + if (pPriv->AdaptorRec->ReputImage) + xf86XVReputImage(pPriv); + break; + } +} + +static void +xf86XVReputOrStopAllPorts(ScrnInfoPtr pScrn, Bool onlyChanged) +{ + ScreenPtr pScreen = pScrn->pScreen; + XvScreenPtr pxvs = GET_XV_SCREEN(pScreen); + XvAdaptorPtr pa; + int c, i; + + for (c = pxvs->nAdaptors, pa = pxvs->pAdaptors; c > 0; c--, pa++) { + XvPortPtr pPort = pa->pPorts; + + for (i = pa->nPorts; i > 0; i--, pPort++) { + XvPortRecPrivatePtr pPriv = (XvPortRecPrivatePtr)pPort->devPriv.ptr; + WindowPtr pWin = (WindowPtr)pPriv->pDraw; + Bool visible; + + if (pPriv->isOn == XV_OFF || !pWin) + continue; + + if (onlyChanged && !pPriv->clipChanged) + continue; + + visible = pWin->visibility == VisibilityUnobscured || + pWin->visibility == VisibilityPartiallyObscured; + + /* + * Stop and remove still/images if + * ReputImage isn't supported. + */ + if (!pPriv->type && !pPriv->AdaptorRec->ReputImage) + visible = FALSE; + + xf86XVReputOrStopPort(pPriv, pWin, visible); + + pPriv->clipChanged = FALSE; + } + } +} + +/**** ScreenRec fields ****/ + +static Bool +xf86XVDestroyWindow(WindowPtr pWin) +{ + ScreenPtr pScreen = pWin->drawable.pScreen; + XF86XVScreenPtr ScreenPriv = GET_XF86XV_SCREEN(pScreen); + XF86XVWindowPtr tmp, WinPriv = GET_XF86XV_WINDOW(pWin); + int ret; + + while(WinPriv) { + XvPortRecPrivatePtr pPriv = WinPriv->PortRec; + + if(pPriv->isOn > XV_OFF) { + (*pPriv->AdaptorRec->StopVideo)( + pPriv->pScrn, pPriv->DevPriv.ptr, TRUE); + pPriv->isOn = XV_OFF; + } + + pPriv->pDraw = NULL; + tmp = WinPriv; + WinPriv = WinPriv->next; + free(tmp); + } + + dixSetPrivate(&pWin->devPrivates, XF86XVWindowKey, NULL); + + pScreen->DestroyWindow = ScreenPriv->DestroyWindow; + ret = (*pScreen->DestroyWindow)(pWin); + pScreen->DestroyWindow = xf86XVDestroyWindow; + + return ret; +} + +static void +xf86XVPostValidateTree(WindowPtr pWin, WindowPtr pLayerWin, VTKind kind) +{ + ScreenPtr pScreen; + XF86XVScreenPtr ScreenPriv; + ScrnInfoPtr pScrn; + + if (pWin) + pScreen = pWin->drawable.pScreen; + else + pScreen = pLayerWin->drawable.pScreen; + + ScreenPriv = GET_XF86XV_SCREEN(pScreen); + pScrn = xf86Screens[pScreen->myNum]; + + xf86XVReputOrStopAllPorts(pScrn, TRUE); + + pScreen->PostValidateTree = ScreenPriv->PostValidateTree; + if (pScreen->PostValidateTree) { + (*pScreen->PostValidateTree)(pWin, pLayerWin, kind); + } + ScreenPriv->PostValidateTree = PostValidateTreeUndefined; +} + +static void +xf86XVWindowExposures(WindowPtr pWin, RegionPtr reg1, RegionPtr reg2) +{ + ScreenPtr pScreen = pWin->drawable.pScreen; + XF86XVScreenPtr ScreenPriv = GET_XF86XV_SCREEN(pScreen); + XF86XVWindowPtr WinPriv = GET_XF86XV_WINDOW(pWin); + XvPortRecPrivatePtr pPriv; + Bool AreasExposed; + + AreasExposed = (WinPriv && reg1 && RegionNotEmpty(reg1)); + + pScreen->WindowExposures = ScreenPriv->WindowExposures; + (*pScreen->WindowExposures)(pWin, reg1, reg2); + pScreen->WindowExposures = xf86XVWindowExposures; + + /* filter out XClearWindow/Area */ + if (!pWin->valdata) return; + + while(WinPriv) { + Bool visible = TRUE; + + pPriv = WinPriv->PortRec; + + /* + * Stop and remove still/images if areas were exposed and + * ReputImage isn't supported. + */ + if (!pPriv->type && !pPriv->AdaptorRec->ReputImage) + visible = !AreasExposed; + + /* + * Subtract exposed areas from overlaid image to match textured video + * behavior. + */ + if (!pPriv->type && pPriv->clientClip) + RegionSubtract(pPriv->clientClip, pPriv->clientClip, reg1); + + if (visible && pPriv->ckeyFilled) { + RegionRec tmp; + RegionNull(&tmp); + RegionCopy(&tmp, reg1); + RegionTranslate(&tmp, pWin->drawable.x, pWin->drawable.y); + RegionSubtract(pPriv->ckeyFilled, pPriv->ckeyFilled, &tmp); + } + + WinPriv = WinPriv->next; + xf86XVReputOrStopPort(pPriv, pWin, visible); + + pPriv->clipChanged = FALSE; + } +} + +static void +xf86XVClipNotify(WindowPtr pWin, int dx, int dy) +{ + ScreenPtr pScreen = pWin->drawable.pScreen; + XF86XVScreenPtr ScreenPriv = GET_XF86XV_SCREEN(pScreen); + XF86XVWindowPtr WinPriv = GET_XF86XV_WINDOW(pWin); + XvPortRecPrivatePtr pPriv; + + while(WinPriv) { + pPriv = WinPriv->PortRec; + + if(pPriv->pCompositeClip && pPriv->FreeCompositeClip) + RegionDestroy(pPriv->pCompositeClip); + + pPriv->pCompositeClip = NULL; + + if (pPriv->AdaptorRec->ClipNotify) + (*pPriv->AdaptorRec->ClipNotify)(pPriv->pScrn, pPriv->DevPriv.ptr, + pWin, dx, dy); + + pPriv->clipChanged = TRUE; + + if (ScreenPriv->PostValidateTree == PostValidateTreeUndefined) { + ScreenPriv->PostValidateTree = pScreen->PostValidateTree; + pScreen->PostValidateTree = xf86XVPostValidateTree; + } + + WinPriv = WinPriv->next; + } + + if(ScreenPriv->ClipNotify) { + pScreen->ClipNotify = ScreenPriv->ClipNotify; + (*pScreen->ClipNotify)(pWin, dx, dy); + pScreen->ClipNotify = xf86XVClipNotify; + } +} + + + +/**** Required XvScreenRec fields ****/ + +static Bool +xf86XVCloseScreen(int i, ScreenPtr pScreen) +{ + ScrnInfoPtr pScrn = xf86Screens[pScreen->myNum]; + XvScreenPtr pxvs = GET_XV_SCREEN(pScreen); + XF86XVScreenPtr ScreenPriv = GET_XF86XV_SCREEN(pScreen); + XvAdaptorPtr pa; + int c; + + if(!ScreenPriv) return TRUE; + + pScreen->DestroyWindow = ScreenPriv->DestroyWindow; + pScreen->WindowExposures = ScreenPriv->WindowExposures; + pScreen->ClipNotify = ScreenPriv->ClipNotify; + + pScrn->EnterVT = ScreenPriv->EnterVT; + pScrn->LeaveVT = ScreenPriv->LeaveVT; + pScrn->AdjustFrame = ScreenPriv->AdjustFrame; + pScrn->ModeSet = ScreenPriv->ModeSet; + + for(c = 0, pa = pxvs->pAdaptors; c < pxvs->nAdaptors; c++, pa++) { + xf86XVFreeAdaptor(pa); + } + + free(pxvs->pAdaptors); + free(ScreenPriv); + return TRUE; +} + + +static int +xf86XVQueryAdaptors( + ScreenPtr pScreen, + XvAdaptorPtr *p_pAdaptors, + int *p_nAdaptors +){ + XvScreenPtr pxvs = GET_XV_SCREEN(pScreen); + + *p_nAdaptors = pxvs->nAdaptors; + *p_pAdaptors = pxvs->pAdaptors; + + return Success; +} + + +/**** ScrnInfoRec fields ****/ + +static Bool +xf86XVEnterVT(int index, int flags) +{ + ScrnInfoPtr pScrn = xf86Screens[index]; + ScreenPtr pScreen = screenInfo.screens[index]; + XF86XVScreenPtr ScreenPriv = GET_XF86XV_SCREEN(pScreen); + Bool ret; + + pScrn->EnterVT = ScreenPriv->EnterVT; + ret = (*ScreenPriv->EnterVT)(index, flags); + ScreenPriv->EnterVT = pScrn->EnterVT; + pScrn->EnterVT = xf86XVEnterVT; + + if(ret) WalkTree(pScreen, xf86XVReputAllVideo, 0); + + return ret; +} + +static void +xf86XVLeaveVT(int index, int flags) +{ + ScrnInfoPtr pScrn = xf86Screens[index]; + ScreenPtr pScreen = screenInfo.screens[index]; + XvScreenPtr pxvs = GET_XV_SCREEN(pScreen); + XF86XVScreenPtr ScreenPriv = GET_XF86XV_SCREEN(pScreen); + XvAdaptorPtr pAdaptor; + XvPortPtr pPort; + XvPortRecPrivatePtr pPriv; + int i, j; + + for(i = 0; i < pxvs->nAdaptors; i++) { + pAdaptor = &pxvs->pAdaptors[i]; + for(j = 0; j < pAdaptor->nPorts; j++) { + pPort = &pAdaptor->pPorts[j]; + pPriv = (XvPortRecPrivatePtr)pPort->devPriv.ptr; + if(pPriv->isOn > XV_OFF) { + + (*pPriv->AdaptorRec->StopVideo)( + pPriv->pScrn, pPriv->DevPriv.ptr, TRUE); + pPriv->isOn = XV_OFF; + + if(pPriv->pCompositeClip && pPriv->FreeCompositeClip) + RegionDestroy(pPriv->pCompositeClip); + + pPriv->pCompositeClip = NULL; + + if(!pPriv->type && pPriv->pDraw) { /* still */ + xf86XVRemovePortFromWindow((WindowPtr)pPriv->pDraw, pPriv); + } + } + } + } + + pScrn->LeaveVT = ScreenPriv->LeaveVT; + (*ScreenPriv->LeaveVT)(index, flags); + ScreenPriv->LeaveVT = pScrn->LeaveVT; + pScrn->LeaveVT = xf86XVLeaveVT; +} + +static void +xf86XVAdjustFrame(int index, int x, int y, int flags) +{ + ScrnInfoPtr pScrn = xf86Screens[index]; + ScreenPtr pScreen = pScrn->pScreen; + XF86XVScreenPtr ScreenPriv = GET_XF86XV_SCREEN(pScreen); + + if(ScreenPriv->AdjustFrame) { + pScrn->AdjustFrame = ScreenPriv->AdjustFrame; + (*pScrn->AdjustFrame)(index, x, y, flags); + pScrn->AdjustFrame = xf86XVAdjustFrame; + } + + xf86XVReputOrStopAllPorts(pScrn, FALSE); +} + +static void +xf86XVModeSet(ScrnInfoPtr pScrn) +{ + ScreenPtr pScreen = pScrn->pScreen; + XF86XVScreenPtr ScreenPriv; + + /* Can be called before pScrn->pScreen is set */ + if (!pScreen) + return; + + ScreenPriv = GET_XF86XV_SCREEN(pScreen); + + if (ScreenPriv->ModeSet) { + pScrn->ModeSet = ScreenPriv->ModeSet; + (*pScrn->ModeSet)(pScrn); + pScrn->ModeSet = xf86XVModeSet; + } + + xf86XVReputOrStopAllPorts(pScrn, FALSE); +} + +/**** XvAdaptorRec fields ****/ + +static int +xf86XVAllocatePort( + unsigned long port, + XvPortPtr pPort, + XvPortPtr *ppPort +){ + *ppPort = pPort; + return Success; +} + + + +static int +xf86XVFreePort(XvPortPtr pPort) +{ + return Success; +} + + +static int +xf86XVPutVideo( + ClientPtr client, + DrawablePtr pDraw, + XvPortPtr pPort, + GCPtr pGC, + INT16 vid_x, INT16 vid_y, + CARD16 vid_w, CARD16 vid_h, + INT16 drw_x, INT16 drw_y, + CARD16 drw_w, CARD16 drw_h +){ + XvPortRecPrivatePtr portPriv = (XvPortRecPrivatePtr)(pPort->devPriv.ptr); + int result; + + /* No dumping video to pixmaps... For now anyhow */ + if(pDraw->type != DRAWABLE_WINDOW) { + pPort->pDraw = (DrawablePtr)NULL; + return BadAlloc; + } + + /* If we are changing windows, unregister our port in the old window */ + if(portPriv->pDraw && (portPriv->pDraw != pDraw)) + xf86XVRemovePortFromWindow((WindowPtr)(portPriv->pDraw), portPriv); + + /* Register our port with the new window */ + result = xf86XVEnlistPortInWindow((WindowPtr)pDraw, portPriv); + if(result != Success) return result; + + portPriv->type = XvInputMask; + + /* save a copy of these parameters */ + portPriv->vid_x = vid_x; portPriv->vid_y = vid_y; + portPriv->vid_w = vid_w; portPriv->vid_h = vid_h; + portPriv->drw_x = drw_x; portPriv->drw_y = drw_y; + portPriv->drw_w = drw_w; portPriv->drw_h = drw_h; + + /* make sure we have the most recent copy of the clientClip */ + xf86XVCopyClip(portPriv, pGC); + + /* To indicate to the DI layer that we were successful */ + pPort->pDraw = pDraw; + + if(!portPriv->pScrn->vtSema) return Success; /* Success ? */ + + return(xf86XVReputVideo(portPriv)); +} + +static int +xf86XVPutStill( + ClientPtr client, + DrawablePtr pDraw, + XvPortPtr pPort, + GCPtr pGC, + INT16 vid_x, INT16 vid_y, + CARD16 vid_w, CARD16 vid_h, + INT16 drw_x, INT16 drw_y, + CARD16 drw_w, CARD16 drw_h +){ + XvPortRecPrivatePtr portPriv = (XvPortRecPrivatePtr)(pPort->devPriv.ptr); + RegionRec WinRegion; + RegionRec ClipRegion; + BoxRec WinBox; + int ret = Success; + Bool clippedAway = FALSE; + + if (pDraw->type != DRAWABLE_WINDOW) + return BadAlloc; + + if(!portPriv->pScrn->vtSema) return Success; /* Success ? */ + + WinBox.x1 = pDraw->x + drw_x; + WinBox.y1 = pDraw->y + drw_y; + WinBox.x2 = WinBox.x1 + drw_w; + WinBox.y2 = WinBox.y1 + drw_h; + + xf86XVCopyCompositeClip(portPriv, pGC, pDraw); + + RegionInit(&WinRegion, &WinBox, 1); + RegionNull(&ClipRegion); + RegionIntersect(&ClipRegion, &WinRegion, pGC->pCompositeClip); + + if(portPriv->AdaptorRec->flags & VIDEO_CLIP_TO_VIEWPORT) { + RegionRec VPReg; + BoxRec VPBox; + + VPBox.x1 = portPriv->pScrn->frameX0; + VPBox.y1 = portPriv->pScrn->frameY0; + VPBox.x2 = portPriv->pScrn->frameX1 + 1; + VPBox.y2 = portPriv->pScrn->frameY1 + 1; + + RegionInit(&VPReg, &VPBox, 1); + RegionIntersect(&ClipRegion, &ClipRegion, &VPReg); + RegionUninit(&VPReg); + } + + if(portPriv->pDraw) { + xf86XVRemovePortFromWindow((WindowPtr)(portPriv->pDraw), portPriv); + } + + if(!RegionNotEmpty(&ClipRegion)) { + clippedAway = TRUE; + goto PUT_STILL_BAILOUT; + } + + if(portPriv->AdaptorRec->flags & VIDEO_NO_CLIPPING) { + BoxPtr clipBox = RegionRects(&ClipRegion); + if( (RegionNumRects(&ClipRegion) != 1) || + (clipBox->x1 != WinBox.x1) || (clipBox->x2 != WinBox.x2) || + (clipBox->y1 != WinBox.y1) || (clipBox->y2 != WinBox.y2)) + { + clippedAway = TRUE; + goto PUT_STILL_BAILOUT; + } + } + + if(portPriv->AdaptorRec->flags & VIDEO_INVERT_CLIPLIST) { + RegionSubtract(&ClipRegion, &WinRegion, &ClipRegion); + } + + ret = (*portPriv->AdaptorRec->PutStill)(portPriv->pScrn, + vid_x, vid_y, WinBox.x1, WinBox.y1, + vid_w, vid_h, drw_w, drw_h, + &ClipRegion, portPriv->DevPriv.ptr, + pDraw); + + if((ret == Success) && + (portPriv->AdaptorRec->flags & VIDEO_OVERLAID_STILLS)) { + + xf86XVEnlistPortInWindow((WindowPtr)pDraw, portPriv); + portPriv->isOn = XV_ON; + portPriv->vid_x = vid_x; portPriv->vid_y = vid_y; + portPriv->vid_w = vid_w; portPriv->vid_h = vid_h; + portPriv->drw_x = drw_x; portPriv->drw_y = drw_y; + portPriv->drw_w = drw_w; portPriv->drw_h = drw_h; + portPriv->type = 0; /* no mask means it's transient and should + not be reput once it's removed */ + pPort->pDraw = pDraw; /* make sure we can get stop requests */ + } + +PUT_STILL_BAILOUT: + + if((clippedAway || (ret != Success)) && (portPriv->isOn == XV_ON)) { + (*portPriv->AdaptorRec->StopVideo)( + portPriv->pScrn, portPriv->DevPriv.ptr, FALSE); + portPriv->isOn = XV_PENDING; + } + + /* This clip was copied and only good for one shot */ + if(!portPriv->FreeCompositeClip) + portPriv->pCompositeClip = NULL; + + RegionUninit(&WinRegion); + RegionUninit(&ClipRegion); + + return ret; +} + +static int +xf86XVGetVideo( + ClientPtr client, + DrawablePtr pDraw, + XvPortPtr pPort, + GCPtr pGC, + INT16 vid_x, INT16 vid_y, + CARD16 vid_w, CARD16 vid_h, + INT16 drw_x, INT16 drw_y, + CARD16 drw_w, CARD16 drw_h +){ + XvPortRecPrivatePtr portPriv = (XvPortRecPrivatePtr)(pPort->devPriv.ptr); + int result; + + /* No pixmaps... For now anyhow */ + if(pDraw->type != DRAWABLE_WINDOW) { + pPort->pDraw = (DrawablePtr)NULL; + return BadAlloc; + } + + /* If we are changing windows, unregister our port in the old window */ + if(portPriv->pDraw && (portPriv->pDraw != pDraw)) + xf86XVRemovePortFromWindow((WindowPtr)(portPriv->pDraw), portPriv); + + /* Register our port with the new window */ + result = xf86XVEnlistPortInWindow((WindowPtr)pDraw, portPriv); + if(result != Success) return result; + + portPriv->type = XvOutputMask; + + /* save a copy of these parameters */ + portPriv->vid_x = vid_x; portPriv->vid_y = vid_y; + portPriv->vid_w = vid_w; portPriv->vid_h = vid_h; + portPriv->drw_x = drw_x; portPriv->drw_y = drw_y; + portPriv->drw_w = drw_w; portPriv->drw_h = drw_h; + + /* make sure we have the most recent copy of the clientClip */ + xf86XVCopyClip(portPriv, pGC); + + /* To indicate to the DI layer that we were successful */ + pPort->pDraw = pDraw; + + if(!portPriv->pScrn->vtSema) return Success; /* Success ? */ + + return(xf86XVRegetVideo(portPriv)); +} + +static int +xf86XVGetStill( + ClientPtr client, + DrawablePtr pDraw, + XvPortPtr pPort, + GCPtr pGC, + INT16 vid_x, INT16 vid_y, + CARD16 vid_w, CARD16 vid_h, + INT16 drw_x, INT16 drw_y, + CARD16 drw_w, CARD16 drw_h +){ + XvPortRecPrivatePtr portPriv = (XvPortRecPrivatePtr)(pPort->devPriv.ptr); + RegionRec WinRegion; + RegionRec ClipRegion; + BoxRec WinBox; + int ret = Success; + Bool clippedAway = FALSE; + + if (pDraw->type != DRAWABLE_WINDOW) + return BadAlloc; + + if(!portPriv->pScrn->vtSema) return Success; /* Success ? */ + + WinBox.x1 = pDraw->x + drw_x; + WinBox.y1 = pDraw->y + drw_y; + WinBox.x2 = WinBox.x1 + drw_w; + WinBox.y2 = WinBox.y1 + drw_h; + + RegionInit(&WinRegion, &WinBox, 1); + RegionNull(&ClipRegion); + RegionIntersect(&ClipRegion, &WinRegion, pGC->pCompositeClip); + + if(portPriv->pDraw) { + xf86XVRemovePortFromWindow((WindowPtr)(portPriv->pDraw), portPriv); + } + + if(!RegionNotEmpty(&ClipRegion)) { + clippedAway = TRUE; + goto GET_STILL_BAILOUT; + } + + if(portPriv->AdaptorRec->flags & VIDEO_INVERT_CLIPLIST) { + RegionSubtract(&ClipRegion, &WinRegion, &ClipRegion); + } + + ret = (*portPriv->AdaptorRec->GetStill)(portPriv->pScrn, + vid_x, vid_y, WinBox.x1, WinBox.y1, + vid_w, vid_h, drw_w, drw_h, + &ClipRegion, portPriv->DevPriv.ptr, + pDraw); + +GET_STILL_BAILOUT: + + if((clippedAway || (ret != Success)) && (portPriv->isOn == XV_ON)) { + (*portPriv->AdaptorRec->StopVideo)( + portPriv->pScrn, portPriv->DevPriv.ptr, FALSE); + portPriv->isOn = XV_PENDING; + } + + RegionUninit(&WinRegion); + RegionUninit(&ClipRegion); + + return ret; +} + + + +static int +xf86XVStopVideo( + ClientPtr client, + XvPortPtr pPort, + DrawablePtr pDraw +){ + XvPortRecPrivatePtr portPriv = (XvPortRecPrivatePtr)(pPort->devPriv.ptr); + + if(pDraw->type != DRAWABLE_WINDOW) + return BadAlloc; + + xf86XVRemovePortFromWindow((WindowPtr)pDraw, portPriv); + + if(!portPriv->pScrn->vtSema) return Success; /* Success ? */ + + /* Must free resources. */ + + if(portPriv->isOn > XV_OFF) { + (*portPriv->AdaptorRec->StopVideo)( + portPriv->pScrn, portPriv->DevPriv.ptr, TRUE); + portPriv->isOn = XV_OFF; + } + + return Success; +} + +static int +xf86XVSetPortAttribute( + ClientPtr client, + XvPortPtr pPort, + Atom attribute, + INT32 value +){ + XvPortRecPrivatePtr portPriv = (XvPortRecPrivatePtr)(pPort->devPriv.ptr); + + return((*portPriv->AdaptorRec->SetPortAttribute)(portPriv->pScrn, + attribute, value, portPriv->DevPriv.ptr)); +} + + +static int +xf86XVGetPortAttribute( + ClientPtr client, + XvPortPtr pPort, + Atom attribute, + INT32 *p_value +){ + XvPortRecPrivatePtr portPriv = (XvPortRecPrivatePtr)(pPort->devPriv.ptr); + + return((*portPriv->AdaptorRec->GetPortAttribute)(portPriv->pScrn, + attribute, p_value, portPriv->DevPriv.ptr)); +} + + + +static int +xf86XVQueryBestSize( + ClientPtr client, + XvPortPtr pPort, + CARD8 motion, + CARD16 vid_w, CARD16 vid_h, + CARD16 drw_w, CARD16 drw_h, + unsigned int *p_w, unsigned int *p_h +){ + XvPortRecPrivatePtr portPriv = (XvPortRecPrivatePtr)(pPort->devPriv.ptr); + + (*portPriv->AdaptorRec->QueryBestSize)(portPriv->pScrn, + (Bool)motion, vid_w, vid_h, drw_w, drw_h, + p_w, p_h, portPriv->DevPriv.ptr); + + return Success; +} + + +static int +xf86XVPutImage( + ClientPtr client, + DrawablePtr pDraw, + XvPortPtr pPort, + GCPtr pGC, + INT16 src_x, INT16 src_y, + CARD16 src_w, CARD16 src_h, + INT16 drw_x, INT16 drw_y, + CARD16 drw_w, CARD16 drw_h, + XvImagePtr format, + unsigned char* data, + Bool sync, + CARD16 width, CARD16 height +){ + XvPortRecPrivatePtr portPriv = (XvPortRecPrivatePtr)(pPort->devPriv.ptr); + RegionRec WinRegion; + RegionRec ClipRegion; + BoxRec WinBox; + int ret = Success; + Bool clippedAway = FALSE; + + if (pDraw->type != DRAWABLE_WINDOW) + return BadAlloc; + + if(!portPriv->pScrn->vtSema) return Success; /* Success ? */ + + xf86XVCopyCompositeClip(portPriv, pGC, pDraw); + + WinBox.x1 = pDraw->x + drw_x; + WinBox.y1 = pDraw->y + drw_y; + WinBox.x2 = WinBox.x1 + drw_w; + WinBox.y2 = WinBox.y1 + drw_h; + + RegionInit(&WinRegion, &WinBox, 1); + RegionNull(&ClipRegion); + RegionIntersect(&ClipRegion, &WinRegion, pGC->pCompositeClip); + + if(portPriv->AdaptorRec->flags & VIDEO_CLIP_TO_VIEWPORT) { + RegionRec VPReg; + BoxRec VPBox; + + VPBox.x1 = portPriv->pScrn->frameX0; + VPBox.y1 = portPriv->pScrn->frameY0; + VPBox.x2 = portPriv->pScrn->frameX1 + 1; + VPBox.y2 = portPriv->pScrn->frameY1 + 1; + + RegionInit(&VPReg, &VPBox, 1); + RegionIntersect(&ClipRegion, &ClipRegion, &VPReg); + RegionUninit(&VPReg); + } + + /* If we are changing windows, unregister our port in the old window */ + if(portPriv->pDraw && (portPriv->pDraw != pDraw)) + xf86XVRemovePortFromWindow((WindowPtr)(portPriv->pDraw), portPriv); + + /* Register our port with the new window */ + ret = xf86XVEnlistPortInWindow((WindowPtr)pDraw, portPriv); + if(ret != Success) goto PUT_IMAGE_BAILOUT; + + if(!RegionNotEmpty(&ClipRegion)) { + clippedAway = TRUE; + goto PUT_IMAGE_BAILOUT; + } + + if(portPriv->AdaptorRec->flags & VIDEO_NO_CLIPPING) { + BoxPtr clipBox = RegionRects(&ClipRegion); + if( (RegionNumRects(&ClipRegion) != 1) || + (clipBox->x1 != WinBox.x1) || (clipBox->x2 != WinBox.x2) || + (clipBox->y1 != WinBox.y1) || (clipBox->y2 != WinBox.y2)) + { + clippedAway = TRUE; + goto PUT_IMAGE_BAILOUT; + } + } + + if(portPriv->AdaptorRec->flags & VIDEO_INVERT_CLIPLIST) { + RegionSubtract(&ClipRegion, &WinRegion, &ClipRegion); + } + + ret = (*portPriv->AdaptorRec->PutImage)(portPriv->pScrn, + src_x, src_y, WinBox.x1, WinBox.y1, + src_w, src_h, drw_w, drw_h, format->id, data, width, height, + sync, &ClipRegion, portPriv->DevPriv.ptr, + pDraw); + + if((ret == Success) && + (portPriv->AdaptorRec->flags & VIDEO_OVERLAID_IMAGES)) { + + portPriv->isOn = XV_ON; + portPriv->vid_x = src_x; portPriv->vid_y = src_y; + portPriv->vid_w = src_w; portPriv->vid_h = src_h; + portPriv->drw_x = drw_x; portPriv->drw_y = drw_y; + portPriv->drw_w = drw_w; portPriv->drw_h = drw_h; + portPriv->type = 0; /* no mask means it's transient and should + not be reput once it's removed */ + pPort->pDraw = pDraw; /* make sure we can get stop requests */ + } + +PUT_IMAGE_BAILOUT: + + if((clippedAway || (ret != Success)) && (portPriv->isOn == XV_ON)) { + (*portPriv->AdaptorRec->StopVideo)( + portPriv->pScrn, portPriv->DevPriv.ptr, FALSE); + portPriv->isOn = XV_PENDING; + } + + /* This clip was copied and only good for one shot */ + if(!portPriv->FreeCompositeClip) + portPriv->pCompositeClip = NULL; + + RegionUninit(&WinRegion); + RegionUninit(&ClipRegion); + + return ret; +} + + +static int +xf86XVQueryImageAttributes( + ClientPtr client, + XvPortPtr pPort, + XvImagePtr format, + CARD16 *width, + CARD16 *height, + int *pitches, + int *offsets +){ + XvPortRecPrivatePtr portPriv = (XvPortRecPrivatePtr)(pPort->devPriv.ptr); + + return (*portPriv->AdaptorRec->QueryImageAttributes)(portPriv->pScrn, + format->id, width, height, pitches, offsets); +} + +void +xf86XVFillKeyHelperDrawable (DrawablePtr pDraw, CARD32 key, RegionPtr fillboxes) +{ + ScreenPtr pScreen = pDraw->pScreen; + ChangeGCVal pval[2]; + BoxPtr pbox = RegionRects(fillboxes); + int i, nbox = RegionNumRects(fillboxes); + xRectangle *rects; + GCPtr gc; + + if(!xf86Screens[pScreen->myNum]->vtSema) return; + + gc = GetScratchGC(pDraw->depth, pScreen); + pval[0].val = key; + pval[1].val = IncludeInferiors; + (void) ChangeGC(NullClient, gc, GCForeground|GCSubwindowMode, pval); + ValidateGC(pDraw, gc); + + rects = malloc(nbox * sizeof(xRectangle)); + + for(i = 0; i < nbox; i++, pbox++) + { + rects[i].x = pbox->x1 - pDraw->x; + rects[i].y = pbox->y1 - pDraw->y; + rects[i].width = pbox->x2 - pbox->x1; + rects[i].height = pbox->y2 - pbox->y1; + } + + (*gc->ops->PolyFillRect)(pDraw, gc, nbox, rects); + + free(rects); + FreeScratchGC (gc); +} + +void +xf86XVFillKeyHelper (ScreenPtr pScreen, CARD32 key, RegionPtr fillboxes) +{ + xf86XVFillKeyHelperDrawable (&pScreen->root->drawable, key, fillboxes); +} + +void +xf86XVFillKeyHelperPort (DrawablePtr pDraw, pointer data, CARD32 key, RegionPtr clipboxes, Bool fillEverything) +{ + WindowPtr pWin = (WindowPtr)pDraw; + XF86XVWindowPtr WinPriv = GET_XF86XV_WINDOW(pWin); + XvPortRecPrivatePtr portPriv = NULL; + RegionRec reg; + RegionPtr fillboxes; + + while (WinPriv) { + XvPortRecPrivatePtr pPriv = WinPriv->PortRec; + + if (data == pPriv->DevPriv.ptr) { + portPriv = pPriv; + break; + } + + WinPriv = WinPriv->next; + } + + if (!portPriv) + return; + + if (!portPriv->ckeyFilled) + portPriv->ckeyFilled = RegionCreate(NULL, 0); + + if (!fillEverything) { + RegionNull(®); + fillboxes = ® + RegionSubtract(fillboxes, clipboxes, portPriv->ckeyFilled); + + if (!RegionNotEmpty(fillboxes)) + goto out; + } else + fillboxes = clipboxes; + + + RegionCopy(portPriv->ckeyFilled, clipboxes); + + xf86XVFillKeyHelperDrawable(pDraw, key, fillboxes); +out: + if (!fillEverything) + RegionUninit(®); +} + + +/* xf86XVClipVideoHelper - + + Takes the dst box in standard X BoxRec form (top and left + edges inclusive, bottom and right exclusive). The new dst + box is returned. The source boundaries are given (x1, y1 + inclusive, x2, y2 exclusive) and returned are the new source + boundaries in 16.16 fixed point. +*/ + +Bool +xf86XVClipVideoHelper( + BoxPtr dst, + INT32 *xa, + INT32 *xb, + INT32 *ya, + INT32 *yb, + RegionPtr reg, + INT32 width, + INT32 height +){ + double xsw, xdw, ysw, ydw; + INT32 delta; + BoxPtr extents = RegionExtents(reg); + int diff; + + xsw = (*xb - *xa) << 16; + xdw = dst->x2 - dst->x1; + ysw = (*yb - *ya) << 16; + ydw = dst->y2 - dst->y1; + + *xa <<= 16; *xb <<= 16; + *ya <<= 16; *yb <<= 16; + + diff = extents->x1 - dst->x1; + if (diff > 0) { + dst->x1 = extents->x1; + *xa += (diff * xsw) / xdw; + } + diff = dst->x2 - extents->x2; + if (diff > 0) { + dst->x2 = extents->x2; + *xb -= (diff * xsw) / xdw; + } + diff = extents->y1 - dst->y1; + if (diff > 0) { + dst->y1 = extents->y1; + *ya += (diff * ysw) / ydw; + } + diff = dst->y2 - extents->y2; + if (diff > 0) { + dst->y2 = extents->y2; + *yb -= (diff * ysw) / ydw; + } + + if (*xa < 0) { + diff = (((-*xa) * xdw) + xsw - 1) / xsw; + dst->x1 += diff; + *xa += (diff * xsw) / xdw; + } + delta = *xb - (width << 16); + if (delta > 0) { + diff = ((delta * xdw) + xsw - 1) / xsw; + dst->x2 -= diff; + *xb -= (diff * xsw) / xdw; + } + if (*xa >= *xb) return FALSE; + + if (*ya < 0) { + diff = (((-*ya) * ydw) + ysw - 1) / ysw; + dst->y1 += diff; + *ya += (diff * ysw) / ydw; + } + delta = *yb - (height << 16); + if (delta > 0) { + diff = ((delta * ydw) + ysw - 1) / ysw; + dst->y2 -= diff; + *yb -= (diff * ysw) / ydw; + } + if (*ya >= *yb) return FALSE; + + if ((dst->x1 > extents->x1) || (dst->x2 < extents->x2) || + (dst->y1 > extents->y1) || (dst->y2 < extents->y2)) + { + RegionRec clipReg; + RegionInit(&clipReg, dst, 1); + RegionIntersect(reg, reg, &clipReg); + RegionUninit(&clipReg); + } + return TRUE; +} + +void +xf86XVCopyYUV12ToPacked( + const void *srcy, + const void *srcv, + const void *srcu, + void *dst, + int srcPitchy, + int srcPitchuv, + int dstPitch, + int h, + int w +){ + CARD32 *Dst; + const CARD8 *Y, *U, *V; + int i, j; + + w >>= 1; + + for (j = 0; j < h; j++) { + Dst = dst; + Y = srcy; V = srcv; U = srcu; + i = w; + while (i >= 4) { +#if X_BYTE_ORDER == X_LITTLE_ENDIAN + Dst[0] = Y[0] | (Y[1] << 16) | (U[0] << 8) | (V[0] << 24); + Dst[1] = Y[2] | (Y[3] << 16) | (U[1] << 8) | (V[1] << 24); + Dst[2] = Y[4] | (Y[5] << 16) | (U[2] << 8) | (V[2] << 24); + Dst[3] = Y[6] | (Y[7] << 16) | (U[3] << 8) | (V[3] << 24); +#else + /* This assumes a little-endian framebuffer */ + Dst[0] = (Y[0] << 24) | (Y[1] << 8) | (U[0] << 16) | V[0]; + Dst[1] = (Y[2] << 24) | (Y[3] << 8) | (U[1] << 16) | V[1]; + Dst[2] = (Y[4] << 24) | (Y[5] << 8) | (U[2] << 16) | V[2]; + Dst[3] = (Y[6] << 24) | (Y[7] << 8) | (U[3] << 16) | V[3]; +#endif + Dst += 4; Y += 8; V += 4; U += 4; + i -= 4; + } + + while (i--) { +#if X_BYTE_ORDER == X_LITTLE_ENDIAN + Dst[0] = Y[0] | (Y[1] << 16) | (U[0] << 8) | (V[0] << 24); +#else + /* This assumes a little-endian framebuffer */ + Dst[0] = (Y[0] << 24) | (Y[1] << 8) | (U[0] << 16) | V[0]; +#endif + Dst++; Y += 2; V++; U++; + } + + dst = (CARD8 *)dst + dstPitch; + srcy = (const CARD8 *)srcy + srcPitchy; + if (j & 1) { + srcu = (const CARD8 *)srcu + srcPitchuv; + srcv = (const CARD8 *)srcv + srcPitchuv; + } + } +} + +void +xf86XVCopyPacked( + const void *src, + void *dst, + int srcPitch, + int dstPitch, + int h, + int w +){ + const CARD32 *Src; + CARD32 *Dst; + int i; + + w >>= 1; + while (--h >= 0) { + do { + Dst = dst; Src = src; + i = w; + while (i >= 4) { + Dst[0] = Src[0]; + Dst[1] = Src[1]; + Dst[2] = Src[2]; + Dst[3] = Src[3]; + Dst += 4; Src += 4; i -= 4; + } + if (!i) break; + Dst[0] = Src[0]; + if (i == 1) break; + Dst[1] = Src[1]; + if (i == 2) break; + Dst[2] = Src[2]; + } while (0); + + src = (const CARD8 *)src + srcPitch; + dst = (CARD8 *)dst + dstPitch; + } +} diff --git a/xorg-server/hw/xfree86/loader/loadmod.c b/xorg-server/hw/xfree86/loader/loadmod.c index 46ce68b86..9f820993a 100644 --- a/xorg-server/hw/xfree86/loader/loadmod.c +++ b/xorg-server/hw/xfree86/loader/loadmod.c @@ -483,19 +483,15 @@ LoaderListDirs(const char **subdirlist, const char **patternlist) char *fp; char **listing = NULL; char **save; + char **ret = NULL; int n = 0; if (!(pathlist = InitPathList(NULL))) return NULL; - if (!(subdirs = InitSubdirs(subdirlist))) { - FreePathList(pathlist); - return NULL; - } - if (!(patterns = InitPatterns(patternlist))) { - FreePathList(pathlist); - FreeSubdirs(subdirs); - return NULL; - } + if (!(subdirs = InitSubdirs(subdirlist))) + goto bail; + if (!(patterns = InitPatterns(patternlist))) + goto bail; for (elem = pathlist; *elem; elem++) { for (s = subdirs; *s; s++) { @@ -529,20 +525,14 @@ LoaderListDirs(const char **subdirlist, const char **patternlist) save[n] = NULL; FreeStringList(save); } - FreePathList(pathlist); - FreeSubdirs(subdirs); - FreePatterns(patterns); closedir(d); - return NULL; + goto bail; } listing[n] = malloc(len + 1); if (!listing[n]) { FreeStringList(listing); - FreePathList(pathlist); - FreeSubdirs(subdirs); - FreePatterns(patterns); closedir(d); - return NULL; + goto bail; } strncpy(listing[n], dp->d_name + match[1].rm_so, len); @@ -558,11 +548,13 @@ LoaderListDirs(const char **subdirlist, const char **patternlist) } if (listing) listing[n] = NULL; + ret = listing; - FreePathList(pathlist); - FreeSubdirs(subdirs); +bail: FreePatterns(patterns); - return listing; + FreeSubdirs(subdirs); + FreePathList(pathlist); + return ret; } void diff --git a/xorg-server/miext/damage/damage.c b/xorg-server/miext/damage/damage.c index 0fe1fb603..d79121165 100644 --- a/xorg-server/miext/damage/damage.c +++ b/xorg-server/miext/damage/damage.c @@ -121,54 +121,6 @@ getDrawableDamageRef (DrawablePtr pDrawable) dixLookupPrivateAddr(&(pWindow)->devPrivates, damageWinPrivateKey) static void -damageReportDamage (DamagePtr pDamage, RegionPtr pDamageRegion) -{ - BoxRec tmpBox; - RegionRec tmpRegion; - Bool was_empty; - - switch (pDamage->damageLevel) { - case DamageReportRawRegion: - RegionUnion(&pDamage->damage, &pDamage->damage, - pDamageRegion); - (*pDamage->damageReport) (pDamage, pDamageRegion, pDamage->closure); - break; - case DamageReportDeltaRegion: - RegionNull(&tmpRegion); - RegionSubtract(&tmpRegion, pDamageRegion, &pDamage->damage); - if (RegionNotEmpty(&tmpRegion)) { - RegionUnion(&pDamage->damage, &pDamage->damage, - pDamageRegion); - (*pDamage->damageReport) (pDamage, &tmpRegion, pDamage->closure); - } - RegionUninit(&tmpRegion); - break; - case DamageReportBoundingBox: - tmpBox = *RegionExtents(&pDamage->damage); - RegionUnion(&pDamage->damage, &pDamage->damage, - pDamageRegion); - if (!BOX_SAME (&tmpBox, RegionExtents(&pDamage->damage))) { - (*pDamage->damageReport) (pDamage, &pDamage->damage, - pDamage->closure); - } - break; - case DamageReportNonEmpty: - was_empty = !RegionNotEmpty(&pDamage->damage); - RegionUnion(&pDamage->damage, &pDamage->damage, - pDamageRegion); - if (was_empty && RegionNotEmpty(&pDamage->damage)) { - (*pDamage->damageReport) (pDamage, &pDamage->damage, - pDamage->closure); - } - break; - case DamageReportNone: - RegionUnion(&pDamage->damage, &pDamage->damage, - pDamageRegion); - break; - } -} - -static void damageReportDamagePostRendering (DamagePtr pDamage, RegionPtr pOldDamage, RegionPtr pDamageRegion) { BoxRec tmpBox; @@ -360,7 +312,7 @@ damageRegionAppend (DrawablePtr pDrawable, RegionPtr pRegion, Bool clip, /* Report damage now, if desired. */ if (!pDamage->reportAfter) { if (pDamage->damageReport) - damageReportDamage (pDamage, pDamageRegion); + DamageReportDamage (pDamage, pDamageRegion); else RegionUnion(&pDamage->damage, &pDamage->damage, pDamageRegion); @@ -393,7 +345,7 @@ damageRegionProcessPending (DrawablePtr pDrawable) if (pDamage->reportAfter) { /* It's possible that there is only interest in postRendering reporting. */ if (pDamage->damageReport) - damageReportDamage (pDamage, &pDamage->pendingDamage); + DamageReportDamage (pDamage, &pDamage->pendingDamage); else RegionUnion(&pDamage->damage, &pDamage->damage, &pDamage->pendingDamage); @@ -2125,3 +2077,52 @@ DamageGetScreenFuncs (ScreenPtr pScreen) damageScrPriv(pScreen); return &pScrPriv->funcs; } + +void +DamageReportDamage (DamagePtr pDamage, RegionPtr pDamageRegion) +{ + BoxRec tmpBox; + RegionRec tmpRegion; + Bool was_empty; + + switch (pDamage->damageLevel) { + case DamageReportRawRegion: + RegionUnion(&pDamage->damage, &pDamage->damage, + pDamageRegion); + (*pDamage->damageReport) (pDamage, pDamageRegion, pDamage->closure); + break; + case DamageReportDeltaRegion: + RegionNull(&tmpRegion); + RegionSubtract(&tmpRegion, pDamageRegion, &pDamage->damage); + if (RegionNotEmpty(&tmpRegion)) { + RegionUnion(&pDamage->damage, &pDamage->damage, + pDamageRegion); + (*pDamage->damageReport) (pDamage, &tmpRegion, pDamage->closure); + } + RegionUninit(&tmpRegion); + break; + case DamageReportBoundingBox: + tmpBox = *RegionExtents(&pDamage->damage); + RegionUnion(&pDamage->damage, &pDamage->damage, + pDamageRegion); + if (!BOX_SAME (&tmpBox, RegionExtents(&pDamage->damage))) { + (*pDamage->damageReport) (pDamage, &pDamage->damage, + pDamage->closure); + } + break; + case DamageReportNonEmpty: + was_empty = !RegionNotEmpty(&pDamage->damage); + RegionUnion(&pDamage->damage, &pDamage->damage, + pDamageRegion); + if (was_empty && RegionNotEmpty(&pDamage->damage)) { + (*pDamage->damageReport) (pDamage, &pDamage->damage, + pDamage->closure); + } + break; + case DamageReportNone: + RegionUnion(&pDamage->damage, &pDamage->damage, + pDamageRegion); + break; + } +} + diff --git a/xorg-server/miext/damage/damage.h b/xorg-server/miext/damage/damage.h index 067016f38..0c7fc316c 100644 --- a/xorg-server/miext/damage/damage.h +++ b/xorg-server/miext/damage/damage.h @@ -110,6 +110,10 @@ DamageRegionProcessPending (DrawablePtr pDrawable); extern _X_EXPORT void DamageRegionRendered (DrawablePtr pDrawable, DamagePtr pDamage, RegionPtr pOldDamage, RegionPtr pRegion); +/* Call this when you create a new Damage and you wish to send an initial damage message (to it). */ +extern _X_EXPORT void +DamageReportDamage (DamagePtr pDamage, RegionPtr pDamageRegion); + /* Avoid using this call, it only exists for API compatibility. */ extern _X_EXPORT void DamageDamageRegion (DrawablePtr pDrawable, diff --git a/xorg-server/os/connection.c b/xorg-server/os/connection.c index 4eb2c15c7..0c580ab5e 100644 --- a/xorg-server/os/connection.c +++ b/xorg-server/os/connection.c @@ -1,1308 +1,1307 @@ -/***********************************************************
-
-Copyright 1987, 1989, 1998 The Open Group
-
-Permission to use, copy, modify, distribute, and sell this software and its
-documentation for any purpose is hereby granted without fee, provided that
-the above copyright notice appear in all copies and that both that
-copyright notice and this permission notice appear in supporting
-documentation.
-
-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
-OPEN GROUP 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.
-
-Except as contained in this notice, the name of The Open Group shall not be
-used in advertising or otherwise to promote the sale, use or other dealings
-in this Software without prior written authorization from The Open Group.
-
-
-Copyright 1987, 1989 by Digital Equipment Corporation, Maynard, Massachusetts.
-
- All Rights Reserved
-
-Permission to use, copy, modify, and distribute this software and its
-documentation for any purpose and without fee is hereby granted,
-provided that the above copyright notice appear in all copies and that
-both that copyright notice and this permission notice appear in
-supporting documentation, and that the name of Digital not be
-used in advertising or publicity pertaining to distribution of the
-software without specific, written prior permission.
-
-DIGITAL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
-ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL
-DIGITAL BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR
-ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
-WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
-ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
-SOFTWARE.
-
-******************************************************************/
-/*****************************************************************
- * Stuff to create connections --- OS dependent
- *
- * EstablishNewConnections, CreateWellKnownSockets, ResetWellKnownSockets,
- * CloseDownConnection, CheckConnections, AddEnabledDevice,
- * RemoveEnabledDevice, OnlyListToOneClient,
- * ListenToAllClients,
- *
- * (WaitForSomething is in its own file)
- *
- * In this implementation, a client socket table is not kept.
- * Instead, what would be the index into the table is just the
- * file descriptor of the socket. This won't work for if the
- * socket ids aren't small nums (0 - 2^8)
- *
- *****************************************************************/
-
-#ifdef HAVE_DIX_CONFIG_H
-#include <dix-config.h>
-#endif
-
-#ifdef WIN32
-#include <X11/Xwinsock.h>
-#endif
-#include <X11/X.h>
-#include <X11/Xproto.h>
-#define XSERV_t
-#define TRANS_SERVER
-#define TRANS_REOPEN
-#include <X11/Xtrans/Xtrans.h>
-#include <X11/Xtrans/Xtransint.h>
-#include <errno.h>
-#include <signal.h>
-#include <stdio.h>
-#include <stdlib.h>
-
-#ifndef WIN32
-#include <sys/socket.h>
-
-
-
-#if defined(TCPCONN) || defined(STREAMSCONN)
-# include <netinet/in.h>
-# include <arpa/inet.h>
-# ifdef apollo
-# ifndef NO_TCP_H
-# include <netinet/tcp.h>
-# endif
-# else
-# ifdef CSRG_BASED
-# include <sys/param.h>
-# endif
-# include <netinet/tcp.h>
-# endif
-# include <arpa/inet.h>
-#endif
-
-#include <sys/uio.h>
-
-#endif /* WIN32 */
-#include "misc.h" /* for typedef of pointer */
-#include "osdep.h"
-#include <X11/Xpoll.h>
-#include "opaque.h"
-#include "dixstruct.h"
-#include "xace.h"
-
-#define Pid_t pid_t
-
-
-#ifdef HAS_GETPEERUCRED
-# include <ucred.h>
-# include <zone.h>
-#endif
-
-#ifdef XSERVER_DTRACE
-# include <sys/types.h>
-typedef const char *string;
-# ifndef HAS_GETPEERUCRED
-# define zoneid_t int
-# endif
-# include "../dix/Xserver-dtrace.h"
-#endif
-
-static int lastfdesc; /* maximum file descriptor */
-
-fd_set WellKnownConnections; /* Listener mask */
-fd_set EnabledDevices; /* mask for input devices that are on */
-fd_set AllSockets; /* select on this */
-fd_set AllClients; /* available clients */
-fd_set LastSelectMask; /* mask returned from last select call */
-fd_set ClientsWithInput; /* clients with FULL requests in buffer */
-fd_set ClientsWriteBlocked; /* clients who cannot receive output */
-fd_set OutputPending; /* clients with reply/event data ready to go */
-int MaxClients = 0;
-Bool NewOutputPending; /* not yet attempted to write some new output */
-Bool AnyClientsWriteBlocked; /* true if some client blocked on write */
-
-static Bool RunFromSmartParent; /* send SIGUSR1 to parent process */
-Bool RunFromSigStopParent; /* send SIGSTOP to our own process; Upstart (or
- equivalent) will send SIGCONT back. */
-Bool PartialNetwork; /* continue even if unable to bind all addrs */
-static Pid_t ParentProcess;
-
-static Bool debug_conns = FALSE;
-
-fd_set IgnoredClientsWithInput;
-static fd_set GrabImperviousClients;
-static fd_set SavedAllClients;
-static fd_set SavedAllSockets;
-static fd_set SavedClientsWithInput;
-int GrabInProgress = 0;
-
-#if !defined(WIN32)
-int *ConnectionTranslation = NULL;
-#else
-/*
- * On NT fds are not between 0 and MAXSOCKS, they are unrelated, and there is
- * not even a known maximum value, so use something quite arbitrary for now.
- * Do storage is a hash table of size 256. Collisions are handled in a linked
- * list.
- */
-
-#undef MAXSOCKS
-#define MAXSOCKS 500
-#undef MAXSELECT
-#define MAXSELECT 500
-
-struct _ct_node {
- struct _ct_node *next;
- int key;
- int value;
-};
-
-struct _ct_node *ct_head[256];
-
-void InitConnectionTranslation(void)
-{
- memset(ct_head, 0, sizeof(ct_head));
-}
-
-int GetConnectionTranslation(int conn)
-{
- struct _ct_node *node = ct_head[conn & 0xff];
- while (node != NULL)
- {
- if (node->key == conn)
- return node->value;
- node = node->next;
- }
- return 0;
-}
-
-void SetConnectionTranslation(int conn, int client)
-{
- struct _ct_node **node = ct_head + (conn & 0xff);
- if (client == 0) /* remove entry */
- {
- while (*node != NULL)
- {
- if ((*node)->key == conn)
- {
- struct _ct_node *temp = *node;
- *node = (*node)->next;
- free(temp);
- return;
- }
- node = &((*node)->next);
- }
- return;
- } else
- {
- while (*node != NULL)
- {
- if ((*node)->key == conn)
- {
- (*node)->value = client;
- return;
- }
- node = &((*node)->next);
- }
- *node = malloc(sizeof(struct _ct_node));
- (*node)->next = NULL;
- (*node)->key = conn;
- (*node)->value = client;
- return;
- }
-}
-
-void ClearConnectionTranslation(void)
-{
- unsigned i;
- for (i = 0; i < 256; i++)
- {
- struct _ct_node *node = ct_head[i];
- while (node != NULL)
- {
- struct _ct_node *temp = node;
- node = node->next;
- free(temp);
- }
- }
-}
-#endif
-
-static XtransConnInfo *ListenTransConns = NULL;
-static int *ListenTransFds = NULL;
-static int ListenTransCount;
-
-static void ErrorConnMax(XtransConnInfo /* trans_conn */);
-
-static XtransConnInfo
-lookup_trans_conn (int fd)
-{
- if (ListenTransFds)
- {
- int i;
- for (i = 0; i < ListenTransCount; i++)
- if (ListenTransFds[i] == fd)
- return ListenTransConns[i];
- }
-
- return NULL;
-}
-
-/* Set MaxClients and lastfdesc, and allocate ConnectionTranslation */
-
-void
-InitConnectionLimits(void)
-{
- lastfdesc = -1;
-
-#ifndef __CYGWIN__
-
-#if !defined(XNO_SYSCONF) && defined(_SC_OPEN_MAX)
- lastfdesc = sysconf(_SC_OPEN_MAX) - 1;
-#endif
-
-#ifdef HAS_GETDTABLESIZE
- if (lastfdesc < 0)
- lastfdesc = getdtablesize() - 1;
-#endif
-
-#ifdef _NFILE
- if (lastfdesc < 0)
- lastfdesc = _NFILE - 1;
-#endif
-
-#endif /* __CYGWIN__ */
-
- /* This is the fallback */
- if (lastfdesc < 0)
- lastfdesc = MAXSOCKS;
-
- if (lastfdesc > MAXSELECT)
- lastfdesc = MAXSELECT;
-
- if (lastfdesc > MAXCLIENTS)
- {
- lastfdesc = MAXCLIENTS;
- if (debug_conns)
- ErrorF( "REACHED MAXIMUM CLIENTS LIMIT %d\n", MAXCLIENTS);
- }
- MaxClients = lastfdesc;
-
-#ifdef DEBUG
- ErrorF("InitConnectionLimits: MaxClients = %d\n", MaxClients);
-#endif
-
-#if !defined(WIN32)
- if (!ConnectionTranslation)
- ConnectionTranslation = (int *)xnfalloc(sizeof(int)*(lastfdesc + 1));
-#else
- InitConnectionTranslation();
-#endif
-}
-
-/*
- * If SIGUSR1 was set to SIG_IGN when the server started, assume that either
- *
- * a- The parent process is ignoring SIGUSR1
- *
- * or
- *
- * b- The parent process is expecting a SIGUSR1
- * when the server is ready to accept connections
- *
- * In the first case, the signal will be harmless, in the second case,
- * the signal will be quite useful.
- */
-static void
-InitParentProcess(void)
-{
-#if !defined(WIN32)
- OsSigHandlerPtr handler;
- handler = OsSignal (SIGUSR1, SIG_IGN);
- if ( handler == SIG_IGN)
- RunFromSmartParent = TRUE;
- OsSignal(SIGUSR1, handler);
- ParentProcess = getppid ();
-#endif
-}
-
-void
-NotifyParentProcess(void)
-{
-#if !defined(WIN32)
- if (RunFromSmartParent) {
- if (ParentProcess > 1) {
- kill (ParentProcess, SIGUSR1);
- }
- }
- if (RunFromSigStopParent)
- raise (SIGSTOP);
-#endif
-}
-
-/*****************
- * CreateWellKnownSockets
- * At initialization, create the sockets to listen on for new clients.
- *****************/
-
-void
-CreateWellKnownSockets(void)
-{
- int i;
- int partial;
- char port[20];
-
- FD_ZERO(&AllSockets);
- FD_ZERO(&AllClients);
- FD_ZERO(&LastSelectMask);
- FD_ZERO(&ClientsWithInput);
-
-#if !defined(WIN32)
- for (i=0; i<MaxClients; i++) ConnectionTranslation[i] = 0;
-#else
- ClearConnectionTranslation();
-#endif
-
- FD_ZERO (&WellKnownConnections);
-
- sprintf (port, "%d", atoi (display));
-
- if ((_XSERVTransMakeAllCOTSServerListeners (port, &partial,
- &ListenTransCount, &ListenTransConns) >= 0) &&
- (ListenTransCount >= 1))
- {
- if (!PartialNetwork && partial)
- {
- FatalError ("Failed to establish all listening sockets");
- }
- else
- {
- ListenTransFds = malloc(ListenTransCount * sizeof (int));
-
- for (i = 0; i < ListenTransCount; i++)
- {
- int fd = _XSERVTransGetConnectionNumber (ListenTransConns[i]);
-
- ListenTransFds[i] = fd;
- FD_SET (fd, &WellKnownConnections);
-
- if (!_XSERVTransIsLocal (ListenTransConns[i]))
- {
- DefineSelf (fd);
- }
- }
- }
- }
-
- if (!XFD_ANYSET (&WellKnownConnections))
- FatalError ("Cannot establish any listening sockets - Make sure an X server isn't already running");
-#if !defined(WIN32)
- OsSignal (SIGPIPE, SIG_IGN);
- OsSignal (SIGHUP, AutoResetServer);
-#endif
- OsSignal (SIGINT, GiveUp);
- OsSignal (SIGTERM, GiveUp);
- XFD_COPYSET (&WellKnownConnections, &AllSockets);
- ResetHosts(display);
-
- InitParentProcess();
-
-#ifdef XDMCP
- XdmcpInit ();
-#endif
-}
-
-void
-ResetWellKnownSockets (void)
-{
- int i;
-
- ResetOsBuffers();
-
- for (i = 0; i < ListenTransCount; i++)
- {
- int status = _XSERVTransResetListener (ListenTransConns[i]);
-
- if (status != TRANS_RESET_NOOP)
- {
- if (status == TRANS_RESET_FAILURE)
- {
- /*
- * ListenTransConns[i] freed by xtrans.
- * Remove it from out list.
- */
-
- FD_CLR (ListenTransFds[i], &WellKnownConnections);
- ListenTransFds[i] = ListenTransFds[ListenTransCount - 1];
- ListenTransConns[i] = ListenTransConns[ListenTransCount - 1];
- ListenTransCount -= 1;
- i -= 1;
- }
- else if (status == TRANS_RESET_NEW_FD)
- {
- /*
- * A new file descriptor was allocated (the old one was closed)
- */
-
- int newfd = _XSERVTransGetConnectionNumber (ListenTransConns[i]);
-
- FD_CLR (ListenTransFds[i], &WellKnownConnections);
- ListenTransFds[i] = newfd;
- FD_SET(newfd, &WellKnownConnections);
- }
- }
- }
-
- ResetAuthorization ();
- ResetHosts(display);
- /*
- * restart XDMCP
- */
-#ifdef XDMCP
- XdmcpReset ();
-#endif
-}
-
-void
-CloseWellKnownConnections(void)
-{
- int i;
-
- for (i = 0; i < ListenTransCount; i++)
- _XSERVTransClose (ListenTransConns[i]);
-}
-
-static void
-AuthAudit (ClientPtr client, Bool letin,
- struct sockaddr *saddr, int len,
- unsigned int proto_n, char *auth_proto, int auth_id)
-{
- char addr[128];
- char *out = addr;
- char client_uid_string[64];
- LocalClientCredRec *lcc;
-#ifdef XSERVER_DTRACE
- pid_t client_pid = -1;
- zoneid_t client_zid = -1;
-#endif
-
- if (!len)
- strcpy(out, "local host");
- else
- switch (saddr->sa_family)
- {
- case AF_UNSPEC:
-#if defined(UNIXCONN) || defined(LOCALCONN)
- case AF_UNIX:
-#endif
- strcpy(out, "local host");
- break;
-#if defined(TCPCONN) || defined(STREAMSCONN)
- case AF_INET:
- sprintf(out, "IP %s",
- inet_ntoa(((struct sockaddr_in *) saddr)->sin_addr));
- break;
-#if defined(IPv6) && defined(AF_INET6)
- case AF_INET6: {
- char ipaddr[INET6_ADDRSTRLEN];
- inet_ntop(AF_INET6, &((struct sockaddr_in6 *) saddr)->sin6_addr,
- ipaddr, sizeof(ipaddr));
- sprintf(out, "IP %s", ipaddr);
- }
- break;
-#endif
-#endif
- default:
- strcpy(out, "unknown address");
- }
-
- if (GetLocalClientCreds(client, &lcc) != -1) {
- int slen; /* length written to client_uid_string */
-
- strcpy(client_uid_string, " ( ");
- slen = 3;
-
- if (lcc->fieldsSet & LCC_UID_SET) {
- snprintf(client_uid_string + slen,
- sizeof(client_uid_string) - slen,
- "uid=%ld ", (long) lcc->euid);
- slen = strlen(client_uid_string);
- }
-
- if (lcc->fieldsSet & LCC_GID_SET) {
- snprintf(client_uid_string + slen,
- sizeof(client_uid_string) - slen,
- "gid=%ld ", (long) lcc->egid);
- slen = strlen(client_uid_string);
- }
-
- if (lcc->fieldsSet & LCC_PID_SET) {
-#ifdef XSERVER_DTRACE
- client_pid = lcc->pid;
-#endif
- snprintf(client_uid_string + slen,
- sizeof(client_uid_string) - slen,
- "pid=%ld ", (long) lcc->pid);
- slen = strlen(client_uid_string);
- }
-
- if (lcc->fieldsSet & LCC_ZID_SET) {
-#ifdef XSERVER_DTRACE
- client_zid = lcc->zoneid;
-#endif
- snprintf(client_uid_string + slen,
- sizeof(client_uid_string) - slen,
- "zoneid=%ld ", (long) lcc->zoneid);
- slen = strlen(client_uid_string);
- }
-
- snprintf(client_uid_string + slen, sizeof(client_uid_string) - slen,
- ")");
- FreeLocalClientCreds(lcc);
- }
- else {
- client_uid_string[0] = '\0';
- }
-
-#ifdef XSERVER_DTRACE
- XSERVER_CLIENT_AUTH(client->index, addr, client_pid, client_zid);
-#endif
- if (auditTrailLevel > 1) {
- if (proto_n)
- AuditF("client %d %s from %s%s\n Auth name: %.*s ID: %d\n",
- client->index, letin ? "connected" : "rejected", addr,
- client_uid_string, (int)proto_n, auth_proto, auth_id);
- else
- AuditF("client %d %s from %s%s\n",
- client->index, letin ? "connected" : "rejected", addr,
- client_uid_string);
-
- }
-}
-
-XID
-AuthorizationIDOfClient(ClientPtr client)
-{
- if (client->osPrivate)
- return ((OsCommPtr)client->osPrivate)->auth_id;
- else
- return None;
-}
-
-
-/*****************************************************************
- * ClientAuthorized
- *
- * Sent by the client at connection setup:
- * typedef struct _xConnClientPrefix {
- * CARD8 byteOrder;
- * BYTE pad;
- * CARD16 majorVersion, minorVersion;
- * CARD16 nbytesAuthProto;
- * CARD16 nbytesAuthString;
- * } xConnClientPrefix;
- *
- * It is hoped that eventually one protocol will be agreed upon. In the
- * mean time, a server that implements a different protocol than the
- * client expects, or a server that only implements the host-based
- * mechanism, will simply ignore this information.
- *
- *****************************************************************/
-
-char *
-ClientAuthorized(ClientPtr client,
- unsigned int proto_n, char *auth_proto,
- unsigned int string_n, char *auth_string)
-{
- OsCommPtr priv;
- Xtransaddr *from = NULL;
- int family;
- int fromlen;
- XID auth_id;
- char *reason = NULL;
- XtransConnInfo trans_conn;
-
- priv = (OsCommPtr)client->osPrivate;
- trans_conn = priv->trans_conn;
-
- /* Allow any client to connect without authorization on a launchd socket,
- because it is securely created -- this prevents a race condition on launch */
- if(trans_conn->flags & TRANS_NOXAUTH) {
- auth_id = (XID) 0L;
- } else {
- auth_id = CheckAuthorization (proto_n, auth_proto, string_n, auth_string, client, &reason);
- }
-
- if (auth_id == (XID) ~0L)
- {
- if (_XSERVTransGetPeerAddr(trans_conn, &family, &fromlen, &from) != -1)
- {
- if (InvalidHost ((struct sockaddr *) from, fromlen, client))
- AuthAudit(client, FALSE, (struct sockaddr *) from,
- fromlen, proto_n, auth_proto, auth_id);
- else
- {
- auth_id = (XID) 0;
-#ifdef XSERVER_DTRACE
- if ((auditTrailLevel > 1) || XSERVER_CLIENT_AUTH_ENABLED())
-#else
- if (auditTrailLevel > 1)
-#endif
- AuthAudit(client, TRUE,
- (struct sockaddr *) from, fromlen,
- proto_n, auth_proto, auth_id);
- }
-
- free(from);
- }
-
- if (auth_id == (XID) ~0L) {
- if (reason)
- return reason;
- else
- return "Client is not authorized to connect to Server";
- }
- }
-#ifdef XSERVER_DTRACE
- else if ((auditTrailLevel > 1) || XSERVER_CLIENT_AUTH_ENABLED())
-#else
- else if (auditTrailLevel > 1)
-#endif
- {
- if (_XSERVTransGetPeerAddr (trans_conn,
- &family, &fromlen, &from) != -1)
- {
- AuthAudit(client, TRUE, (struct sockaddr *) from, fromlen,
- proto_n, auth_proto, auth_id);
-
- free(from);
- }
- }
- priv->auth_id = auth_id;
- priv->conn_time = 0;
-
-#ifdef XDMCP
- /* indicate to Xdmcp protocol that we've opened new client */
- XdmcpOpenDisplay(priv->fd);
-#endif /* XDMCP */
-
- XaceHook(XACE_AUTH_AVAIL, client, auth_id);
-
- /* At this point, if the client is authorized to change the access control
- * list, we should getpeername() information, and add the client to
- * the selfhosts list. It's not really the host machine, but the
- * true purpose of the selfhosts list is to see who may change the
- * access control list.
- */
- return((char *)NULL);
-}
-
-static ClientPtr
-AllocNewConnection (XtransConnInfo trans_conn, int fd, CARD32 conn_time)
-{
- OsCommPtr oc;
- ClientPtr client;
-
- if (
-#ifndef WIN32
- fd >= lastfdesc
-#else
- XFD_SETCOUNT(&AllClients) >= MaxClients
-#endif
- )
- return NullClient;
- oc = malloc(sizeof(OsCommRec));
- if (!oc)
- return NullClient;
- oc->trans_conn = trans_conn;
- oc->fd = fd;
- oc->input = (ConnectionInputPtr)NULL;
- oc->output = (ConnectionOutputPtr)NULL;
- oc->auth_id = None;
- oc->conn_time = conn_time;
- if (!(client = NextAvailableClient((pointer)oc)))
- {
- free(oc);
- return NullClient;
- }
- oc->local_client = ComputeLocalClient(client);
-#if !defined(WIN32)
- ConnectionTranslation[fd] = client->index;
-#else
- SetConnectionTranslation(fd, client->index);
-#endif
- if (GrabInProgress)
- {
- FD_SET(fd, &SavedAllClients);
- FD_SET(fd, &SavedAllSockets);
- }
- else
- {
- FD_SET(fd, &AllClients);
- FD_SET(fd, &AllSockets);
- }
-
-#ifdef DEBUG
- ErrorF("AllocNewConnection: client index = %d, socket fd = %d\n",
- client->index, fd);
-#endif
-#ifdef XSERVER_DTRACE
- XSERVER_CLIENT_CONNECT(client->index, fd);
-#endif
-
- return client;
-}
-
-/*****************
- * EstablishNewConnections
- * If anyone is waiting on listened sockets, accept them.
- * Returns a mask with indices of new clients. Updates AllClients
- * and AllSockets.
- *****************/
-
-/*ARGSUSED*/
-Bool
-EstablishNewConnections(ClientPtr clientUnused, pointer closure)
-{
- fd_set readyconnections; /* set of listeners that are ready */
- int curconn; /* fd of listener that's ready */
- register int newconn; /* fd of new client */
- CARD32 connect_time;
- register int i;
- register ClientPtr client;
- register OsCommPtr oc;
- fd_set tmask;
-
- XFD_ANDSET (&tmask, (fd_set*)closure, &WellKnownConnections);
- XFD_COPYSET(&tmask, &readyconnections);
- if (!XFD_ANYSET(&readyconnections))
- return TRUE;
- connect_time = GetTimeInMillis();
- /* kill off stragglers */
- for (i=1; i<currentMaxClients; i++)
- {
- if ((client = clients[i]))
- {
- oc = (OsCommPtr)(client->osPrivate);
- if ((oc && (oc->conn_time != 0) &&
- (connect_time - oc->conn_time) >= TimeOutValue) ||
- (client->noClientException != Success && !client->clientGone))
- CloseDownClient(client);
- }
- }
-#ifndef WIN32
- for (i = 0; i < howmany(XFD_SETSIZE, NFDBITS); i++)
- {
- while (readyconnections.fds_bits[i])
-#else
- for (i = 0; i < XFD_SETCOUNT(&readyconnections); i++)
-#endif
- {
- XtransConnInfo trans_conn, new_trans_conn;
- int status;
-
-#ifndef WIN32
- curconn = mffs (readyconnections.fds_bits[i]) - 1;
- readyconnections.fds_bits[i] &= ~((fd_mask)1 << curconn);
- curconn += (i * (sizeof(fd_mask)*8));
-#else
- curconn = XFD_FD(&readyconnections, i);
-#endif
-
- if ((trans_conn = lookup_trans_conn (curconn)) == NULL)
- continue;
-
- if ((new_trans_conn = _XSERVTransAccept (trans_conn, &status)) == NULL)
- continue;
-
- newconn = _XSERVTransGetConnectionNumber (new_trans_conn);
-
- if (newconn < lastfdesc)
- {
- int clientid;
-#if !defined(WIN32)
- clientid = ConnectionTranslation[newconn];
-#else
- clientid = GetConnectionTranslation(newconn);
-#endif
- if(clientid && (client = clients[clientid]))
- CloseDownClient(client);
- }
-
- _XSERVTransSetOption(new_trans_conn, TRANS_NONBLOCKING, 1);
-
- if (!AllocNewConnection (new_trans_conn, newconn, connect_time))
- {
- ErrorConnMax(new_trans_conn);
- _XSERVTransClose(new_trans_conn);
- }
-
- if(trans_conn->flags & TRANS_NOXAUTH)
- new_trans_conn->flags = new_trans_conn->flags | TRANS_NOXAUTH;
-
- }
-#ifndef WIN32
- }
-#endif
- return TRUE;
-}
-
-#define NOROOM "Maximum number of clients reached"
-
-/************
- * ErrorConnMax
- * Fail a connection due to lack of client or file descriptor space
- ************/
-
-static void
-ErrorConnMax(XtransConnInfo trans_conn)
-{
- int fd = _XSERVTransGetConnectionNumber (trans_conn);
- xConnSetupPrefix csp;
- char pad[3];
- struct iovec iov[3];
- char byteOrder = 0;
- int whichbyte = 1;
- struct timeval waittime;
- fd_set mask;
-
- /* if these seems like a lot of trouble to go to, it probably is */
- waittime.tv_sec = BOTIMEOUT / MILLI_PER_SECOND;
- waittime.tv_usec = (BOTIMEOUT % MILLI_PER_SECOND) *
- (1000000 / MILLI_PER_SECOND);
- FD_ZERO(&mask);
- FD_SET(fd, &mask);
- (void)Select(fd + 1, &mask, NULL, NULL, &waittime);
- /* try to read the byte-order of the connection */
- (void)_XSERVTransRead(trans_conn, &byteOrder, 1);
- if ((byteOrder == 'l') || (byteOrder == 'B'))
- {
- csp.success = xFalse;
- csp.lengthReason = sizeof(NOROOM) - 1;
- csp.length = (sizeof(NOROOM) + 2) >> 2;
- csp.majorVersion = X_PROTOCOL;
- csp.minorVersion = X_PROTOCOL_REVISION;
- if (((*(char *) &whichbyte) && (byteOrder == 'B')) ||
- (!(*(char *) &whichbyte) && (byteOrder == 'l')))
- {
- swaps(&csp.majorVersion, whichbyte);
- swaps(&csp.minorVersion, whichbyte);
- swaps(&csp.length, whichbyte);
- }
- iov[0].iov_len = sz_xConnSetupPrefix;
- iov[0].iov_base = (char *) &csp;
- iov[1].iov_len = csp.lengthReason;
- iov[1].iov_base = NOROOM;
- iov[2].iov_len = (4 - (csp.lengthReason & 3)) & 3;
- iov[2].iov_base = pad;
- (void)_XSERVTransWritev(trans_conn, iov, 3);
- }
-}
-
-/************
- * CloseDownFileDescriptor:
- * Remove this file descriptor and it's I/O buffers, etc.
- ************/
-
-static void
-CloseDownFileDescriptor(OsCommPtr oc)
-{
- int connection = oc->fd;
-
- if (oc->trans_conn) {
- _XSERVTransDisconnect(oc->trans_conn);
- _XSERVTransClose(oc->trans_conn);
- }
-#ifndef WIN32
- ConnectionTranslation[connection] = 0;
-#else
- SetConnectionTranslation(connection, 0);
-#endif
- FD_CLR(connection, &AllSockets);
- FD_CLR(connection, &AllClients);
- FD_CLR(connection, &ClientsWithInput);
- FD_CLR(connection, &GrabImperviousClients);
- if (GrabInProgress)
- {
- FD_CLR(connection, &SavedAllSockets);
- FD_CLR(connection, &SavedAllClients);
- FD_CLR(connection, &SavedClientsWithInput);
- }
- FD_CLR(connection, &ClientsWriteBlocked);
- if (!XFD_ANYSET(&ClientsWriteBlocked))
- AnyClientsWriteBlocked = FALSE;
- FD_CLR(connection, &OutputPending);
-}
-
-/*****************
- * CheckConnections
- * Some connection has died, go find which one and shut it down
- * The file descriptor has been closed, but is still in AllClients.
- * If would truly be wonderful if select() would put the bogus
- * file descriptors in the exception mask, but nooooo. So we have
- * to check each and every socket individually.
- *****************/
-
-void
-CheckConnections(void)
-{
-#ifndef WIN32
- fd_mask mask;
-#endif
- fd_set tmask;
- int curclient, curoff;
- int i;
- struct timeval notime;
- int r;
-#ifdef WIN32
- fd_set savedAllClients;
-#endif
-
- notime.tv_sec = 0;
- notime.tv_usec = 0;
-
-#ifndef WIN32
- for (i=0; i<howmany(XFD_SETSIZE, NFDBITS); i++)
- {
- mask = AllClients.fds_bits[i];
- while (mask)
- {
- curoff = mffs (mask) - 1;
- curclient = curoff + (i * (sizeof(fd_mask)*8));
- FD_ZERO(&tmask);
- FD_SET(curclient, &tmask);
- do {
- r = Select (curclient + 1, &tmask, NULL, NULL, ¬ime);
- } while (r < 0 && (errno == EINTR || errno == EAGAIN));
- if (r < 0)
- if (ConnectionTranslation[curclient] > 0)
- CloseDownClient(clients[ConnectionTranslation[curclient]]);
- mask &= ~((fd_mask)1 << curoff);
- }
- }
-#else
- XFD_COPYSET(&AllClients, &savedAllClients);
- for (i = 0; i < XFD_SETCOUNT(&savedAllClients); i++)
- {
- curclient = XFD_FD(&savedAllClients, i);
- FD_ZERO(&tmask);
- FD_SET(curclient, &tmask);
- do {
- r = Select (curclient + 1, &tmask, NULL, NULL, ¬ime);
- } while (r < 0 && (errno == EINTR || errno == EAGAIN));
- if (r < 0)
- if (GetConnectionTranslation(curclient) > 0)
- CloseDownClient(clients[GetConnectionTranslation(curclient)]);
- }
-#endif
-}
-
-
-/*****************
- * CloseDownConnection
- * Delete client from AllClients and free resources
- *****************/
-
-void
-CloseDownConnection(ClientPtr client)
-{
- OsCommPtr oc = (OsCommPtr)client->osPrivate;
-
- if (FlushCallback)
- CallCallbacks(&FlushCallback, NULL);
-
- if (oc->output && oc->output->count)
- FlushClient(client, oc, (char *)NULL, 0);
-#ifdef XDMCP
- XdmcpCloseDisplay(oc->fd);
-#endif
- CloseDownFileDescriptor(oc);
- FreeOsBuffers(oc);
- free(client->osPrivate);
- client->osPrivate = (pointer)NULL;
- if (auditTrailLevel > 1)
- AuditF("client %d disconnected\n", client->index);
-}
-
-void
-AddGeneralSocket(int fd)
-{
- FD_SET(fd, &AllSockets);
- if (GrabInProgress)
- FD_SET(fd, &SavedAllSockets);
-}
-
-void
-AddEnabledDevice(int fd)
-{
- FD_SET(fd, &EnabledDevices);
- AddGeneralSocket(fd);
-}
-
-void
-RemoveGeneralSocket(int fd)
-{
- FD_CLR(fd, &AllSockets);
- if (GrabInProgress)
- FD_CLR(fd, &SavedAllSockets);
-}
-
-void
-RemoveEnabledDevice(int fd)
-{
- FD_CLR(fd, &EnabledDevices);
- RemoveGeneralSocket(fd);
-}
-
-/*****************
- * OnlyListenToOneClient:
- * Only accept requests from one client. Continue to handle new
- * connections, but don't take any protocol requests from the new
- * ones. Note that if GrabInProgress is set, EstablishNewConnections
- * needs to put new clients into SavedAllSockets and SavedAllClients.
- * Note also that there is no timeout for this in the protocol.
- * This routine is "undone" by ListenToAllClients()
- *****************/
-
-int
-OnlyListenToOneClient(ClientPtr client)
-{
- OsCommPtr oc = (OsCommPtr)client->osPrivate;
- int rc, connection = oc->fd;
-
- rc = XaceHook(XACE_SERVER_ACCESS, client, DixGrabAccess);
- if (rc != Success)
- return rc;
-
- if (! GrabInProgress)
- {
- XFD_COPYSET(&ClientsWithInput, &SavedClientsWithInput);
- XFD_ANDSET(&ClientsWithInput,
- &ClientsWithInput, &GrabImperviousClients);
- if (FD_ISSET(connection, &SavedClientsWithInput))
- {
- FD_CLR(connection, &SavedClientsWithInput);
- FD_SET(connection, &ClientsWithInput);
- }
- XFD_UNSET(&SavedClientsWithInput, &GrabImperviousClients);
- XFD_COPYSET(&AllSockets, &SavedAllSockets);
- XFD_COPYSET(&AllClients, &SavedAllClients);
- XFD_UNSET(&AllSockets, &AllClients);
- XFD_ANDSET(&AllClients, &AllClients, &GrabImperviousClients);
- FD_SET(connection, &AllClients);
- XFD_ORSET(&AllSockets, &AllSockets, &AllClients);
- GrabInProgress = client->index;
- }
- return rc;
-}
-
-/****************
- * ListenToAllClients:
- * Undoes OnlyListentToOneClient()
- ****************/
-
-void
-ListenToAllClients(void)
-{
- if (GrabInProgress)
- {
- XFD_ORSET(&AllSockets, &AllSockets, &SavedAllSockets);
- XFD_ORSET(&AllClients, &AllClients, &SavedAllClients);
- XFD_ORSET(&ClientsWithInput, &ClientsWithInput, &SavedClientsWithInput);
- GrabInProgress = 0;
- }
-}
-
-/****************
- * IgnoreClient
- * Removes one client from input masks.
- * Must have cooresponding call to AttendClient.
- ****************/
-
-void
-IgnoreClient (ClientPtr client)
-{
- OsCommPtr oc = (OsCommPtr)client->osPrivate;
- int connection = oc->fd;
-
- client->ignoreCount++;
- if (client->ignoreCount > 1)
- return;
-
- isItTimeToYield = TRUE;
- if (!GrabInProgress || FD_ISSET(connection, &AllClients))
- {
- if (FD_ISSET (connection, &ClientsWithInput))
- FD_SET(connection, &IgnoredClientsWithInput);
- else
- FD_CLR(connection, &IgnoredClientsWithInput);
- FD_CLR(connection, &ClientsWithInput);
- FD_CLR(connection, &AllSockets);
- FD_CLR(connection, &AllClients);
- FD_CLR(connection, &LastSelectMask);
- }
- else
- {
- if (FD_ISSET (connection, &SavedClientsWithInput))
- FD_SET(connection, &IgnoredClientsWithInput);
- else
- FD_CLR(connection, &IgnoredClientsWithInput);
- FD_CLR(connection, &SavedClientsWithInput);
- FD_CLR(connection, &SavedAllSockets);
- FD_CLR(connection, &SavedAllClients);
- }
-}
-
-/****************
- * AttendClient
- * Adds one client back into the input masks.
- ****************/
-
-void
-AttendClient (ClientPtr client)
-{
- OsCommPtr oc = (OsCommPtr)client->osPrivate;
- int connection = oc->fd;
-
- client->ignoreCount--;
- if (client->ignoreCount)
- return;
-
- if (!GrabInProgress || GrabInProgress == client->index ||
- FD_ISSET(connection, &GrabImperviousClients))
- {
- FD_SET(connection, &AllClients);
- FD_SET(connection, &AllSockets);
- FD_SET(connection, &LastSelectMask);
- if (FD_ISSET (connection, &IgnoredClientsWithInput))
- FD_SET(connection, &ClientsWithInput);
- }
- else
- {
- FD_SET(connection, &SavedAllClients);
- FD_SET(connection, &SavedAllSockets);
- if (FD_ISSET(connection, &IgnoredClientsWithInput))
- FD_SET(connection, &SavedClientsWithInput);
- }
-}
-
-/* make client impervious to grabs; assume only executing client calls this */
-
-void
-MakeClientGrabImpervious(ClientPtr client)
-{
- OsCommPtr oc = (OsCommPtr)client->osPrivate;
- int connection = oc->fd;
-
- FD_SET(connection, &GrabImperviousClients);
-
- if (ServerGrabCallback)
- {
- ServerGrabInfoRec grabinfo;
- grabinfo.client = client;
- grabinfo.grabstate = CLIENT_IMPERVIOUS;
- CallCallbacks(&ServerGrabCallback, &grabinfo);
- }
-}
-
-/* make client pervious to grabs; assume only executing client calls this */
-
-void
-MakeClientGrabPervious(ClientPtr client)
-{
- OsCommPtr oc = (OsCommPtr)client->osPrivate;
- int connection = oc->fd;
-
- FD_CLR(connection, &GrabImperviousClients);
- if (GrabInProgress && (GrabInProgress != client->index))
- {
- if (FD_ISSET(connection, &ClientsWithInput))
- {
- FD_SET(connection, &SavedClientsWithInput);
- FD_CLR(connection, &ClientsWithInput);
- }
- FD_CLR(connection, &AllSockets);
- FD_CLR(connection, &AllClients);
- isItTimeToYield = TRUE;
- }
-
- if (ServerGrabCallback)
- {
- ServerGrabInfoRec grabinfo;
- grabinfo.client = client;
- grabinfo.grabstate = CLIENT_PERVIOUS;
- CallCallbacks(&ServerGrabCallback, &grabinfo);
- }
-}
-
-#ifdef XQUARTZ
-/* Add a fd (from launchd) to our listeners */
-void ListenOnOpenFD(int fd, int noxauth) {
- char port[256];
- XtransConnInfo ciptr;
- const char *display_env = getenv("DISPLAY");
-
- if(display_env && (strncmp(display_env, "/tmp/launch", 11) == 0)) {
- /* Make the path the launchd socket if our DISPLAY is set right */
- strcpy(port, display_env);
- } else {
- /* Just some default so things don't break and die. */
- sprintf(port, ":%d", atoi(display));
- }
-
- /* Make our XtransConnInfo
- * TRANS_SOCKET_LOCAL_INDEX = 5 from Xtrans.c
- */
- ciptr = _XSERVTransReopenCOTSServer(5, fd, port);
- if(ciptr == NULL) {
- ErrorF("Got NULL while trying to Reopen launchd port.\n");
- return;
- }
-
- if(noxauth)
- ciptr->flags = ciptr->flags | TRANS_NOXAUTH;
-
- /* Allocate space to store it */
- ListenTransFds = (int *) realloc(ListenTransFds, (ListenTransCount + 1) * sizeof (int));
- ListenTransConns = (XtransConnInfo *) realloc(ListenTransConns, (ListenTransCount + 1) * sizeof (XtransConnInfo));
-
- /* Store it */
- ListenTransConns[ListenTransCount] = ciptr;
- ListenTransFds[ListenTransCount] = fd;
-
- FD_SET(fd, &WellKnownConnections);
- FD_SET(fd, &AllSockets);
-
- /* Increment the count */
- ListenTransCount++;
-
- /* This *might* not be needed... /shrug */
- ResetAuthorization();
- ResetHosts(display);
-#ifdef XDMCP
- XdmcpReset();
-#endif
-}
-
-#endif
+/*********************************************************** + +Copyright 1987, 1989, 1998 The Open Group + +Permission to use, copy, modify, distribute, and sell this software and its +documentation for any purpose is hereby granted without fee, provided that +the above copyright notice appear in all copies and that both that +copyright notice and this permission notice appear in supporting +documentation. + +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 +OPEN GROUP 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. + +Except as contained in this notice, the name of The Open Group shall not be +used in advertising or otherwise to promote the sale, use or other dealings +in this Software without prior written authorization from The Open Group. + + +Copyright 1987, 1989 by Digital Equipment Corporation, Maynard, Massachusetts. + + All Rights Reserved + +Permission to use, copy, modify, and distribute this software and its +documentation for any purpose and without fee is hereby granted, +provided that the above copyright notice appear in all copies and that +both that copyright notice and this permission notice appear in +supporting documentation, and that the name of Digital not be +used in advertising or publicity pertaining to distribution of the +software without specific, written prior permission. + +DIGITAL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING +ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL +DIGITAL BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR +ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, +WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, +ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS +SOFTWARE. + +******************************************************************/ +/***************************************************************** + * Stuff to create connections --- OS dependent + * + * EstablishNewConnections, CreateWellKnownSockets, ResetWellKnownSockets, + * CloseDownConnection, CheckConnections, AddEnabledDevice, + * RemoveEnabledDevice, OnlyListToOneClient, + * ListenToAllClients, + * + * (WaitForSomething is in its own file) + * + * In this implementation, a client socket table is not kept. + * Instead, what would be the index into the table is just the + * file descriptor of the socket. This won't work for if the + * socket ids aren't small nums (0 - 2^8) + * + *****************************************************************/ + +#ifdef HAVE_DIX_CONFIG_H +#include <dix-config.h> +#endif + +#ifdef WIN32 +#include <X11/Xwinsock.h> +#endif +#include <X11/X.h> +#include <X11/Xproto.h> +#define XSERV_t +#define TRANS_SERVER +#define TRANS_REOPEN +#include <X11/Xtrans/Xtrans.h> +#include <X11/Xtrans/Xtransint.h> +#include <errno.h> +#include <signal.h> +#include <stdio.h> +#include <stdlib.h> + +#ifndef WIN32 +#include <sys/socket.h> + + + +#if defined(TCPCONN) || defined(STREAMSCONN) +# include <netinet/in.h> +# include <arpa/inet.h> +# ifdef apollo +# ifndef NO_TCP_H +# include <netinet/tcp.h> +# endif +# else +# ifdef CSRG_BASED +# include <sys/param.h> +# endif +# include <netinet/tcp.h> +# endif +# include <arpa/inet.h> +#endif + +#include <sys/uio.h> + +#endif /* WIN32 */ +#include "misc.h" /* for typedef of pointer */ +#include "osdep.h" +#include <X11/Xpoll.h> +#include "opaque.h" +#include "dixstruct.h" +#include "xace.h" + +#define Pid_t pid_t + + +#ifdef HAS_GETPEERUCRED +# include <ucred.h> +# include <zone.h> +#endif + +#ifdef XSERVER_DTRACE +# include <sys/types.h> +typedef const char *string; +# ifndef HAS_GETPEERUCRED +# define zoneid_t int +# endif +# include "../dix/Xserver-dtrace.h" +#endif + +static int lastfdesc; /* maximum file descriptor */ + +fd_set WellKnownConnections; /* Listener mask */ +fd_set EnabledDevices; /* mask for input devices that are on */ +fd_set AllSockets; /* select on this */ +fd_set AllClients; /* available clients */ +fd_set LastSelectMask; /* mask returned from last select call */ +fd_set ClientsWithInput; /* clients with FULL requests in buffer */ +fd_set ClientsWriteBlocked; /* clients who cannot receive output */ +fd_set OutputPending; /* clients with reply/event data ready to go */ +int MaxClients = 0; +Bool NewOutputPending; /* not yet attempted to write some new output */ +Bool AnyClientsWriteBlocked; /* true if some client blocked on write */ + +static Bool RunFromSmartParent; /* send SIGUSR1 to parent process */ +Bool RunFromSigStopParent; /* send SIGSTOP to our own process; Upstart (or + equivalent) will send SIGCONT back. */ +Bool PartialNetwork; /* continue even if unable to bind all addrs */ +static Pid_t ParentProcess; + +static Bool debug_conns = FALSE; + +fd_set IgnoredClientsWithInput; +static fd_set GrabImperviousClients; +static fd_set SavedAllClients; +static fd_set SavedAllSockets; +static fd_set SavedClientsWithInput; +int GrabInProgress = 0; + +#if !defined(WIN32) +int *ConnectionTranslation = NULL; +#else +/* + * On NT fds are not between 0 and MAXSOCKS, they are unrelated, and there is + * not even a known maximum value, so use something quite arbitrary for now. + * Do storage is a hash table of size 256. Collisions are handled in a linked + * list. + */ + +#undef MAXSOCKS +#define MAXSOCKS 500 +#undef MAXSELECT +#define MAXSELECT 500 + +struct _ct_node { + struct _ct_node *next; + int key; + int value; +}; + +struct _ct_node *ct_head[256]; + +void InitConnectionTranslation(void) +{ + memset(ct_head, 0, sizeof(ct_head)); +} + +int GetConnectionTranslation(int conn) +{ + struct _ct_node *node = ct_head[conn & 0xff]; + while (node != NULL) + { + if (node->key == conn) + return node->value; + node = node->next; + } + return 0; +} + +void SetConnectionTranslation(int conn, int client) +{ + struct _ct_node **node = ct_head + (conn & 0xff); + if (client == 0) /* remove entry */ + { + while (*node != NULL) + { + if ((*node)->key == conn) + { + struct _ct_node *temp = *node; + *node = (*node)->next; + free(temp); + return; + } + node = &((*node)->next); + } + return; + } else + { + while (*node != NULL) + { + if ((*node)->key == conn) + { + (*node)->value = client; + return; + } + node = &((*node)->next); + } + *node = malloc(sizeof(struct _ct_node)); + (*node)->next = NULL; + (*node)->key = conn; + (*node)->value = client; + return; + } +} + +void ClearConnectionTranslation(void) +{ + unsigned i; + for (i = 0; i < 256; i++) + { + struct _ct_node *node = ct_head[i]; + while (node != NULL) + { + struct _ct_node *temp = node; + node = node->next; + free(temp); + } + } +} +#endif + +static XtransConnInfo *ListenTransConns = NULL; +static int *ListenTransFds = NULL; +static int ListenTransCount; + +static void ErrorConnMax(XtransConnInfo /* trans_conn */); + +static XtransConnInfo +lookup_trans_conn (int fd) +{ + if (ListenTransFds) + { + int i; + for (i = 0; i < ListenTransCount; i++) + if (ListenTransFds[i] == fd) + return ListenTransConns[i]; + } + + return NULL; +} + +/* Set MaxClients and lastfdesc, and allocate ConnectionTranslation */ + +void +InitConnectionLimits(void) +{ + lastfdesc = -1; + +#ifndef __CYGWIN__ + +#if !defined(XNO_SYSCONF) && defined(_SC_OPEN_MAX) + lastfdesc = sysconf(_SC_OPEN_MAX) - 1; +#endif + +#ifdef HAS_GETDTABLESIZE + if (lastfdesc < 0) + lastfdesc = getdtablesize() - 1; +#endif + +#ifdef _NFILE + if (lastfdesc < 0) + lastfdesc = _NFILE - 1; +#endif + +#endif /* __CYGWIN__ */ + + /* This is the fallback */ + if (lastfdesc < 0) + lastfdesc = MAXSOCKS; + + if (lastfdesc > MAXSELECT) + lastfdesc = MAXSELECT; + + if (lastfdesc > MAXCLIENTS) + { + lastfdesc = MAXCLIENTS; + if (debug_conns) + ErrorF( "REACHED MAXIMUM CLIENTS LIMIT %d\n", MAXCLIENTS); + } + MaxClients = lastfdesc; + +#ifdef DEBUG + ErrorF("InitConnectionLimits: MaxClients = %d\n", MaxClients); +#endif + +#if !defined(WIN32) + if (!ConnectionTranslation) + ConnectionTranslation = (int *)xnfalloc(sizeof(int)*(lastfdesc + 1)); +#else + InitConnectionTranslation(); +#endif +} + +/* + * If SIGUSR1 was set to SIG_IGN when the server started, assume that either + * + * a- The parent process is ignoring SIGUSR1 + * + * or + * + * b- The parent process is expecting a SIGUSR1 + * when the server is ready to accept connections + * + * In the first case, the signal will be harmless, in the second case, + * the signal will be quite useful. + */ +static void +InitParentProcess(void) +{ +#if !defined(WIN32) + OsSigHandlerPtr handler; + handler = OsSignal (SIGUSR1, SIG_IGN); + if ( handler == SIG_IGN) + RunFromSmartParent = TRUE; + OsSignal(SIGUSR1, handler); + ParentProcess = getppid (); +#endif +} + +void +NotifyParentProcess(void) +{ +#if !defined(WIN32) + if (RunFromSmartParent) { + if (ParentProcess > 1) { + kill (ParentProcess, SIGUSR1); + } + } + if (RunFromSigStopParent) + raise (SIGSTOP); +#endif +} + +/***************** + * CreateWellKnownSockets + * At initialization, create the sockets to listen on for new clients. + *****************/ + +void +CreateWellKnownSockets(void) +{ + int i; + int partial; + char port[20]; + + FD_ZERO(&AllSockets); + FD_ZERO(&AllClients); + FD_ZERO(&LastSelectMask); + FD_ZERO(&ClientsWithInput); + +#if !defined(WIN32) + for (i=0; i<MaxClients; i++) ConnectionTranslation[i] = 0; +#else + ClearConnectionTranslation(); +#endif + + FD_ZERO (&WellKnownConnections); + + sprintf (port, "%d", atoi (display)); + + if ((_XSERVTransMakeAllCOTSServerListeners (port, &partial, + &ListenTransCount, &ListenTransConns) >= 0) && + (ListenTransCount >= 1)) + { + if (!PartialNetwork && partial) + { + FatalError ("Failed to establish all listening sockets"); + } + else + { + ListenTransFds = malloc(ListenTransCount * sizeof (int)); + + for (i = 0; i < ListenTransCount; i++) + { + int fd = _XSERVTransGetConnectionNumber (ListenTransConns[i]); + + ListenTransFds[i] = fd; + FD_SET (fd, &WellKnownConnections); + + if (!_XSERVTransIsLocal (ListenTransConns[i])) + { + DefineSelf (fd); + } + } + } + } + + if (!XFD_ANYSET (&WellKnownConnections)) + FatalError ("Cannot establish any listening sockets - Make sure an X server isn't already running"); +#if !defined(WIN32) + OsSignal (SIGPIPE, SIG_IGN); + OsSignal (SIGHUP, AutoResetServer); +#endif + OsSignal (SIGINT, GiveUp); + OsSignal (SIGTERM, GiveUp); + XFD_COPYSET (&WellKnownConnections, &AllSockets); + ResetHosts(display); + + InitParentProcess(); + +#ifdef XDMCP + XdmcpInit (); +#endif +} + +void +ResetWellKnownSockets (void) +{ + int i; + + ResetOsBuffers(); + + for (i = 0; i < ListenTransCount; i++) + { + int status = _XSERVTransResetListener (ListenTransConns[i]); + + if (status != TRANS_RESET_NOOP) + { + if (status == TRANS_RESET_FAILURE) + { + /* + * ListenTransConns[i] freed by xtrans. + * Remove it from out list. + */ + + FD_CLR (ListenTransFds[i], &WellKnownConnections); + ListenTransFds[i] = ListenTransFds[ListenTransCount - 1]; + ListenTransConns[i] = ListenTransConns[ListenTransCount - 1]; + ListenTransCount -= 1; + i -= 1; + } + else if (status == TRANS_RESET_NEW_FD) + { + /* + * A new file descriptor was allocated (the old one was closed) + */ + + int newfd = _XSERVTransGetConnectionNumber (ListenTransConns[i]); + + FD_CLR (ListenTransFds[i], &WellKnownConnections); + ListenTransFds[i] = newfd; + FD_SET(newfd, &WellKnownConnections); + } + } + } + + ResetAuthorization (); + ResetHosts(display); + /* + * restart XDMCP + */ +#ifdef XDMCP + XdmcpReset (); +#endif +} + +void +CloseWellKnownConnections(void) +{ + int i; + + for (i = 0; i < ListenTransCount; i++) + _XSERVTransClose (ListenTransConns[i]); +} + +static void +AuthAudit (ClientPtr client, Bool letin, + struct sockaddr *saddr, int len, + unsigned int proto_n, char *auth_proto, int auth_id) +{ + char addr[128]; + char *out = addr; + char client_uid_string[64]; + LocalClientCredRec *lcc; +#ifdef XSERVER_DTRACE + pid_t client_pid = -1; + zoneid_t client_zid = -1; +#endif + + if (!len) + strcpy(out, "local host"); + else + switch (saddr->sa_family) + { + case AF_UNSPEC: +#if defined(UNIXCONN) || defined(LOCALCONN) + case AF_UNIX: +#endif + strcpy(out, "local host"); + break; +#if defined(TCPCONN) || defined(STREAMSCONN) + case AF_INET: + sprintf(out, "IP %s", + inet_ntoa(((struct sockaddr_in *) saddr)->sin_addr)); + break; +#if defined(IPv6) && defined(AF_INET6) + case AF_INET6: { + char ipaddr[INET6_ADDRSTRLEN]; + inet_ntop(AF_INET6, &((struct sockaddr_in6 *) saddr)->sin6_addr, + ipaddr, sizeof(ipaddr)); + sprintf(out, "IP %s", ipaddr); + } + break; +#endif +#endif + default: + strcpy(out, "unknown address"); + } + + if (GetLocalClientCreds(client, &lcc) != -1) { + int slen; /* length written to client_uid_string */ + + strcpy(client_uid_string, " ( "); + slen = 3; + + if (lcc->fieldsSet & LCC_UID_SET) { + snprintf(client_uid_string + slen, + sizeof(client_uid_string) - slen, + "uid=%ld ", (long) lcc->euid); + slen = strlen(client_uid_string); + } + + if (lcc->fieldsSet & LCC_GID_SET) { + snprintf(client_uid_string + slen, + sizeof(client_uid_string) - slen, + "gid=%ld ", (long) lcc->egid); + slen = strlen(client_uid_string); + } + + if (lcc->fieldsSet & LCC_PID_SET) { +#ifdef XSERVER_DTRACE + client_pid = lcc->pid; +#endif + snprintf(client_uid_string + slen, + sizeof(client_uid_string) - slen, + "pid=%ld ", (long) lcc->pid); + slen = strlen(client_uid_string); + } + + if (lcc->fieldsSet & LCC_ZID_SET) { +#ifdef XSERVER_DTRACE + client_zid = lcc->zoneid; +#endif + snprintf(client_uid_string + slen, + sizeof(client_uid_string) - slen, + "zoneid=%ld ", (long) lcc->zoneid); + slen = strlen(client_uid_string); + } + + snprintf(client_uid_string + slen, sizeof(client_uid_string) - slen, + ")"); + FreeLocalClientCreds(lcc); + } + else { + client_uid_string[0] = '\0'; + } + +#ifdef XSERVER_DTRACE + XSERVER_CLIENT_AUTH(client->index, addr, client_pid, client_zid); +#endif + if (auditTrailLevel > 1) { + if (proto_n) + AuditF("client %d %s from %s%s\n Auth name: %.*s ID: %d\n", + client->index, letin ? "connected" : "rejected", addr, + client_uid_string, (int)proto_n, auth_proto, auth_id); + else + AuditF("client %d %s from %s%s\n", + client->index, letin ? "connected" : "rejected", addr, + client_uid_string); + + } +} + +XID +AuthorizationIDOfClient(ClientPtr client) +{ + if (client->osPrivate) + return ((OsCommPtr)client->osPrivate)->auth_id; + else + return None; +} + + +/***************************************************************** + * ClientAuthorized + * + * Sent by the client at connection setup: + * typedef struct _xConnClientPrefix { + * CARD8 byteOrder; + * BYTE pad; + * CARD16 majorVersion, minorVersion; + * CARD16 nbytesAuthProto; + * CARD16 nbytesAuthString; + * } xConnClientPrefix; + * + * It is hoped that eventually one protocol will be agreed upon. In the + * mean time, a server that implements a different protocol than the + * client expects, or a server that only implements the host-based + * mechanism, will simply ignore this information. + * + *****************************************************************/ + +char * +ClientAuthorized(ClientPtr client, + unsigned int proto_n, char *auth_proto, + unsigned int string_n, char *auth_string) +{ + OsCommPtr priv; + Xtransaddr *from = NULL; + int family; + int fromlen; + XID auth_id; + char *reason = NULL; + XtransConnInfo trans_conn; + + priv = (OsCommPtr)client->osPrivate; + trans_conn = priv->trans_conn; + + /* Allow any client to connect without authorization on a launchd socket, + because it is securely created -- this prevents a race condition on launch */ + if(trans_conn->flags & TRANS_NOXAUTH) { + auth_id = (XID) 0L; + } else { + auth_id = CheckAuthorization (proto_n, auth_proto, string_n, auth_string, client, &reason); + } + + if (auth_id == (XID) ~0L) + { + if (_XSERVTransGetPeerAddr(trans_conn, &family, &fromlen, &from) != -1) + { + if (InvalidHost ((struct sockaddr *) from, fromlen, client)) + AuthAudit(client, FALSE, (struct sockaddr *) from, + fromlen, proto_n, auth_proto, auth_id); + else + { + auth_id = (XID) 0; +#ifdef XSERVER_DTRACE + if ((auditTrailLevel > 1) || XSERVER_CLIENT_AUTH_ENABLED()) +#else + if (auditTrailLevel > 1) +#endif + AuthAudit(client, TRUE, + (struct sockaddr *) from, fromlen, + proto_n, auth_proto, auth_id); + } + + free(from); + } + + if (auth_id == (XID) ~0L) { + if (reason) + return reason; + else + return "Client is not authorized to connect to Server"; + } + } +#ifdef XSERVER_DTRACE + else if ((auditTrailLevel > 1) || XSERVER_CLIENT_AUTH_ENABLED()) +#else + else if (auditTrailLevel > 1) +#endif + { + if (_XSERVTransGetPeerAddr (trans_conn, + &family, &fromlen, &from) != -1) + { + AuthAudit(client, TRUE, (struct sockaddr *) from, fromlen, + proto_n, auth_proto, auth_id); + + free(from); + } + } + priv->auth_id = auth_id; + priv->conn_time = 0; + +#ifdef XDMCP + /* indicate to Xdmcp protocol that we've opened new client */ + XdmcpOpenDisplay(priv->fd); +#endif /* XDMCP */ + + XaceHook(XACE_AUTH_AVAIL, client, auth_id); + + /* At this point, if the client is authorized to change the access control + * list, we should getpeername() information, and add the client to + * the selfhosts list. It's not really the host machine, but the + * true purpose of the selfhosts list is to see who may change the + * access control list. + */ + return((char *)NULL); +} + +static ClientPtr +AllocNewConnection (XtransConnInfo trans_conn, int fd, CARD32 conn_time) +{ + OsCommPtr oc; + ClientPtr client; + + if ( +#ifndef WIN32 + fd >= lastfdesc +#else + XFD_SETCOUNT(&AllClients) >= MaxClients +#endif + ) + return NullClient; + oc = malloc(sizeof(OsCommRec)); + if (!oc) + return NullClient; + oc->trans_conn = trans_conn; + oc->fd = fd; + oc->input = (ConnectionInputPtr)NULL; + oc->output = (ConnectionOutputPtr)NULL; + oc->auth_id = None; + oc->conn_time = conn_time; + if (!(client = NextAvailableClient((pointer)oc))) + { + free(oc); + return NullClient; + } + oc->local_client = ComputeLocalClient(client); +#if !defined(WIN32) + ConnectionTranslation[fd] = client->index; +#else + SetConnectionTranslation(fd, client->index); +#endif + if (GrabInProgress) + { + FD_SET(fd, &SavedAllClients); + FD_SET(fd, &SavedAllSockets); + } + else + { + FD_SET(fd, &AllClients); + FD_SET(fd, &AllSockets); + } + +#ifdef DEBUG + ErrorF("AllocNewConnection: client index = %d, socket fd = %d\n", + client->index, fd); +#endif +#ifdef XSERVER_DTRACE + XSERVER_CLIENT_CONNECT(client->index, fd); +#endif + + return client; +} + +/***************** + * EstablishNewConnections + * If anyone is waiting on listened sockets, accept them. + * Returns a mask with indices of new clients. Updates AllClients + * and AllSockets. + *****************/ + +/*ARGSUSED*/ +Bool +EstablishNewConnections(ClientPtr clientUnused, pointer closure) +{ + fd_set readyconnections; /* set of listeners that are ready */ + int curconn; /* fd of listener that's ready */ + register int newconn; /* fd of new client */ + CARD32 connect_time; + register int i; + register ClientPtr client; + register OsCommPtr oc; + fd_set tmask; + + XFD_ANDSET (&tmask, (fd_set*)closure, &WellKnownConnections); + XFD_COPYSET(&tmask, &readyconnections); + if (!XFD_ANYSET(&readyconnections)) + return TRUE; + connect_time = GetTimeInMillis(); + /* kill off stragglers */ + for (i=1; i<currentMaxClients; i++) + { + if ((client = clients[i])) + { + oc = (OsCommPtr)(client->osPrivate); + if ((oc && (oc->conn_time != 0) && + (connect_time - oc->conn_time) >= TimeOutValue) || + (client->noClientException != Success && !client->clientGone)) + CloseDownClient(client); + } + } +#ifndef WIN32 + for (i = 0; i < howmany(XFD_SETSIZE, NFDBITS); i++) + { + while (readyconnections.fds_bits[i]) +#else + for (i = 0; i < XFD_SETCOUNT(&readyconnections); i++) +#endif + { + XtransConnInfo trans_conn, new_trans_conn; + int status; + +#ifndef WIN32 + curconn = mffs (readyconnections.fds_bits[i]) - 1; + readyconnections.fds_bits[i] &= ~((fd_mask)1 << curconn); + curconn += (i * (sizeof(fd_mask)*8)); +#else + curconn = XFD_FD(&readyconnections, i); +#endif + + if ((trans_conn = lookup_trans_conn (curconn)) == NULL) + continue; + + if ((new_trans_conn = _XSERVTransAccept (trans_conn, &status)) == NULL) + continue; + + newconn = _XSERVTransGetConnectionNumber (new_trans_conn); + + if (newconn < lastfdesc) + { + int clientid; +#if !defined(WIN32) + clientid = ConnectionTranslation[newconn]; +#else + clientid = GetConnectionTranslation(newconn); +#endif + if(clientid && (client = clients[clientid])) + CloseDownClient(client); + } + + _XSERVTransSetOption(new_trans_conn, TRANS_NONBLOCKING, 1); + + if(trans_conn->flags & TRANS_NOXAUTH) + new_trans_conn->flags = new_trans_conn->flags | TRANS_NOXAUTH; + + if (!AllocNewConnection (new_trans_conn, newconn, connect_time)) + { + ErrorConnMax(new_trans_conn); + _XSERVTransClose(new_trans_conn); + } + } +#ifndef WIN32 + } +#endif + return TRUE; +} + +#define NOROOM "Maximum number of clients reached" + +/************ + * ErrorConnMax + * Fail a connection due to lack of client or file descriptor space + ************/ + +static void +ErrorConnMax(XtransConnInfo trans_conn) +{ + int fd = _XSERVTransGetConnectionNumber (trans_conn); + xConnSetupPrefix csp; + char pad[3]; + struct iovec iov[3]; + char byteOrder = 0; + int whichbyte = 1; + struct timeval waittime; + fd_set mask; + + /* if these seems like a lot of trouble to go to, it probably is */ + waittime.tv_sec = BOTIMEOUT / MILLI_PER_SECOND; + waittime.tv_usec = (BOTIMEOUT % MILLI_PER_SECOND) * + (1000000 / MILLI_PER_SECOND); + FD_ZERO(&mask); + FD_SET(fd, &mask); + (void)Select(fd + 1, &mask, NULL, NULL, &waittime); + /* try to read the byte-order of the connection */ + (void)_XSERVTransRead(trans_conn, &byteOrder, 1); + if ((byteOrder == 'l') || (byteOrder == 'B')) + { + csp.success = xFalse; + csp.lengthReason = sizeof(NOROOM) - 1; + csp.length = (sizeof(NOROOM) + 2) >> 2; + csp.majorVersion = X_PROTOCOL; + csp.minorVersion = X_PROTOCOL_REVISION; + if (((*(char *) &whichbyte) && (byteOrder == 'B')) || + (!(*(char *) &whichbyte) && (byteOrder == 'l'))) + { + swaps(&csp.majorVersion, whichbyte); + swaps(&csp.minorVersion, whichbyte); + swaps(&csp.length, whichbyte); + } + iov[0].iov_len = sz_xConnSetupPrefix; + iov[0].iov_base = (char *) &csp; + iov[1].iov_len = csp.lengthReason; + iov[1].iov_base = NOROOM; + iov[2].iov_len = (4 - (csp.lengthReason & 3)) & 3; + iov[2].iov_base = pad; + (void)_XSERVTransWritev(trans_conn, iov, 3); + } +} + +/************ + * CloseDownFileDescriptor: + * Remove this file descriptor and it's I/O buffers, etc. + ************/ + +static void +CloseDownFileDescriptor(OsCommPtr oc) +{ + int connection = oc->fd; + + if (oc->trans_conn) { + _XSERVTransDisconnect(oc->trans_conn); + _XSERVTransClose(oc->trans_conn); + } +#ifndef WIN32 + ConnectionTranslation[connection] = 0; +#else + SetConnectionTranslation(connection, 0); +#endif + FD_CLR(connection, &AllSockets); + FD_CLR(connection, &AllClients); + FD_CLR(connection, &ClientsWithInput); + FD_CLR(connection, &GrabImperviousClients); + if (GrabInProgress) + { + FD_CLR(connection, &SavedAllSockets); + FD_CLR(connection, &SavedAllClients); + FD_CLR(connection, &SavedClientsWithInput); + } + FD_CLR(connection, &ClientsWriteBlocked); + if (!XFD_ANYSET(&ClientsWriteBlocked)) + AnyClientsWriteBlocked = FALSE; + FD_CLR(connection, &OutputPending); +} + +/***************** + * CheckConnections + * Some connection has died, go find which one and shut it down + * The file descriptor has been closed, but is still in AllClients. + * If would truly be wonderful if select() would put the bogus + * file descriptors in the exception mask, but nooooo. So we have + * to check each and every socket individually. + *****************/ + +void +CheckConnections(void) +{ +#ifndef WIN32 + fd_mask mask; +#endif + fd_set tmask; + int curclient, curoff; + int i; + struct timeval notime; + int r; +#ifdef WIN32 + fd_set savedAllClients; +#endif + + notime.tv_sec = 0; + notime.tv_usec = 0; + +#ifndef WIN32 + for (i=0; i<howmany(XFD_SETSIZE, NFDBITS); i++) + { + mask = AllClients.fds_bits[i]; + while (mask) + { + curoff = mffs (mask) - 1; + curclient = curoff + (i * (sizeof(fd_mask)*8)); + FD_ZERO(&tmask); + FD_SET(curclient, &tmask); + do { + r = Select (curclient + 1, &tmask, NULL, NULL, ¬ime); + } while (r < 0 && (errno == EINTR || errno == EAGAIN)); + if (r < 0) + if (ConnectionTranslation[curclient] > 0) + CloseDownClient(clients[ConnectionTranslation[curclient]]); + mask &= ~((fd_mask)1 << curoff); + } + } +#else + XFD_COPYSET(&AllClients, &savedAllClients); + for (i = 0; i < XFD_SETCOUNT(&savedAllClients); i++) + { + curclient = XFD_FD(&savedAllClients, i); + FD_ZERO(&tmask); + FD_SET(curclient, &tmask); + do { + r = Select (curclient + 1, &tmask, NULL, NULL, ¬ime); + } while (r < 0 && (errno == EINTR || errno == EAGAIN)); + if (r < 0) + if (GetConnectionTranslation(curclient) > 0) + CloseDownClient(clients[GetConnectionTranslation(curclient)]); + } +#endif +} + + +/***************** + * CloseDownConnection + * Delete client from AllClients and free resources + *****************/ + +void +CloseDownConnection(ClientPtr client) +{ + OsCommPtr oc = (OsCommPtr)client->osPrivate; + + if (FlushCallback) + CallCallbacks(&FlushCallback, NULL); + + if (oc->output && oc->output->count) + FlushClient(client, oc, (char *)NULL, 0); +#ifdef XDMCP + XdmcpCloseDisplay(oc->fd); +#endif + CloseDownFileDescriptor(oc); + FreeOsBuffers(oc); + free(client->osPrivate); + client->osPrivate = (pointer)NULL; + if (auditTrailLevel > 1) + AuditF("client %d disconnected\n", client->index); +} + +void +AddGeneralSocket(int fd) +{ + FD_SET(fd, &AllSockets); + if (GrabInProgress) + FD_SET(fd, &SavedAllSockets); +} + +void +AddEnabledDevice(int fd) +{ + FD_SET(fd, &EnabledDevices); + AddGeneralSocket(fd); +} + +void +RemoveGeneralSocket(int fd) +{ + FD_CLR(fd, &AllSockets); + if (GrabInProgress) + FD_CLR(fd, &SavedAllSockets); +} + +void +RemoveEnabledDevice(int fd) +{ + FD_CLR(fd, &EnabledDevices); + RemoveGeneralSocket(fd); +} + +/***************** + * OnlyListenToOneClient: + * Only accept requests from one client. Continue to handle new + * connections, but don't take any protocol requests from the new + * ones. Note that if GrabInProgress is set, EstablishNewConnections + * needs to put new clients into SavedAllSockets and SavedAllClients. + * Note also that there is no timeout for this in the protocol. + * This routine is "undone" by ListenToAllClients() + *****************/ + +int +OnlyListenToOneClient(ClientPtr client) +{ + OsCommPtr oc = (OsCommPtr)client->osPrivate; + int rc, connection = oc->fd; + + rc = XaceHook(XACE_SERVER_ACCESS, client, DixGrabAccess); + if (rc != Success) + return rc; + + if (! GrabInProgress) + { + XFD_COPYSET(&ClientsWithInput, &SavedClientsWithInput); + XFD_ANDSET(&ClientsWithInput, + &ClientsWithInput, &GrabImperviousClients); + if (FD_ISSET(connection, &SavedClientsWithInput)) + { + FD_CLR(connection, &SavedClientsWithInput); + FD_SET(connection, &ClientsWithInput); + } + XFD_UNSET(&SavedClientsWithInput, &GrabImperviousClients); + XFD_COPYSET(&AllSockets, &SavedAllSockets); + XFD_COPYSET(&AllClients, &SavedAllClients); + XFD_UNSET(&AllSockets, &AllClients); + XFD_ANDSET(&AllClients, &AllClients, &GrabImperviousClients); + FD_SET(connection, &AllClients); + XFD_ORSET(&AllSockets, &AllSockets, &AllClients); + GrabInProgress = client->index; + } + return rc; +} + +/**************** + * ListenToAllClients: + * Undoes OnlyListentToOneClient() + ****************/ + +void +ListenToAllClients(void) +{ + if (GrabInProgress) + { + XFD_ORSET(&AllSockets, &AllSockets, &SavedAllSockets); + XFD_ORSET(&AllClients, &AllClients, &SavedAllClients); + XFD_ORSET(&ClientsWithInput, &ClientsWithInput, &SavedClientsWithInput); + GrabInProgress = 0; + } +} + +/**************** + * IgnoreClient + * Removes one client from input masks. + * Must have cooresponding call to AttendClient. + ****************/ + +void +IgnoreClient (ClientPtr client) +{ + OsCommPtr oc = (OsCommPtr)client->osPrivate; + int connection = oc->fd; + + client->ignoreCount++; + if (client->ignoreCount > 1) + return; + + isItTimeToYield = TRUE; + if (!GrabInProgress || FD_ISSET(connection, &AllClients)) + { + if (FD_ISSET (connection, &ClientsWithInput)) + FD_SET(connection, &IgnoredClientsWithInput); + else + FD_CLR(connection, &IgnoredClientsWithInput); + FD_CLR(connection, &ClientsWithInput); + FD_CLR(connection, &AllSockets); + FD_CLR(connection, &AllClients); + FD_CLR(connection, &LastSelectMask); + } + else + { + if (FD_ISSET (connection, &SavedClientsWithInput)) + FD_SET(connection, &IgnoredClientsWithInput); + else + FD_CLR(connection, &IgnoredClientsWithInput); + FD_CLR(connection, &SavedClientsWithInput); + FD_CLR(connection, &SavedAllSockets); + FD_CLR(connection, &SavedAllClients); + } +} + +/**************** + * AttendClient + * Adds one client back into the input masks. + ****************/ + +void +AttendClient (ClientPtr client) +{ + OsCommPtr oc = (OsCommPtr)client->osPrivate; + int connection = oc->fd; + + client->ignoreCount--; + if (client->ignoreCount) + return; + + if (!GrabInProgress || GrabInProgress == client->index || + FD_ISSET(connection, &GrabImperviousClients)) + { + FD_SET(connection, &AllClients); + FD_SET(connection, &AllSockets); + FD_SET(connection, &LastSelectMask); + if (FD_ISSET (connection, &IgnoredClientsWithInput)) + FD_SET(connection, &ClientsWithInput); + } + else + { + FD_SET(connection, &SavedAllClients); + FD_SET(connection, &SavedAllSockets); + if (FD_ISSET(connection, &IgnoredClientsWithInput)) + FD_SET(connection, &SavedClientsWithInput); + } +} + +/* make client impervious to grabs; assume only executing client calls this */ + +void +MakeClientGrabImpervious(ClientPtr client) +{ + OsCommPtr oc = (OsCommPtr)client->osPrivate; + int connection = oc->fd; + + FD_SET(connection, &GrabImperviousClients); + + if (ServerGrabCallback) + { + ServerGrabInfoRec grabinfo; + grabinfo.client = client; + grabinfo.grabstate = CLIENT_IMPERVIOUS; + CallCallbacks(&ServerGrabCallback, &grabinfo); + } +} + +/* make client pervious to grabs; assume only executing client calls this */ + +void +MakeClientGrabPervious(ClientPtr client) +{ + OsCommPtr oc = (OsCommPtr)client->osPrivate; + int connection = oc->fd; + + FD_CLR(connection, &GrabImperviousClients); + if (GrabInProgress && (GrabInProgress != client->index)) + { + if (FD_ISSET(connection, &ClientsWithInput)) + { + FD_SET(connection, &SavedClientsWithInput); + FD_CLR(connection, &ClientsWithInput); + } + FD_CLR(connection, &AllSockets); + FD_CLR(connection, &AllClients); + isItTimeToYield = TRUE; + } + + if (ServerGrabCallback) + { + ServerGrabInfoRec grabinfo; + grabinfo.client = client; + grabinfo.grabstate = CLIENT_PERVIOUS; + CallCallbacks(&ServerGrabCallback, &grabinfo); + } +} + +#ifdef XQUARTZ +/* Add a fd (from launchd) to our listeners */ +void ListenOnOpenFD(int fd, int noxauth) { + char port[256]; + XtransConnInfo ciptr; + const char *display_env = getenv("DISPLAY"); + + if(display_env && (strncmp(display_env, "/tmp/launch", 11) == 0)) { + /* Make the path the launchd socket if our DISPLAY is set right */ + strcpy(port, display_env); + } else { + /* Just some default so things don't break and die. */ + sprintf(port, ":%d", atoi(display)); + } + + /* Make our XtransConnInfo + * TRANS_SOCKET_LOCAL_INDEX = 5 from Xtrans.c + */ + ciptr = _XSERVTransReopenCOTSServer(5, fd, port); + if(ciptr == NULL) { + ErrorF("Got NULL while trying to Reopen launchd port.\n"); + return; + } + + if(noxauth) + ciptr->flags = ciptr->flags | TRANS_NOXAUTH; + + /* Allocate space to store it */ + ListenTransFds = (int *) realloc(ListenTransFds, (ListenTransCount + 1) * sizeof (int)); + ListenTransConns = (XtransConnInfo *) realloc(ListenTransConns, (ListenTransCount + 1) * sizeof (XtransConnInfo)); + + /* Store it */ + ListenTransConns[ListenTransCount] = ciptr; + ListenTransFds[ListenTransCount] = fd; + + FD_SET(fd, &WellKnownConnections); + FD_SET(fd, &AllSockets); + + /* Increment the count */ + ListenTransCount++; + + /* This *might* not be needed... /shrug */ + ResetAuthorization(); + ResetHosts(display); +#ifdef XDMCP + XdmcpReset(); +#endif +} + +#endif diff --git a/xorg-server/randr/rrdispatch.c b/xorg-server/randr/rrdispatch.c index ac4d2acc1..213550475 100644 --- a/xorg-server/randr/rrdispatch.c +++ b/xorg-server/randr/rrdispatch.c @@ -146,7 +146,7 @@ ProcRRSelectInput (ClientPtr client) /* * Now see if the client needs an event */ - if (pScrPriv && (pRREvent->mask & RRScreenChangeNotifyMask)) + if (pScrPriv) { pTimes = &((RRTimesPtr) (pRRClient + 1))[pScreen->myNum]; if (CompareTimeStamps (pTimes->setTime, @@ -154,7 +154,35 @@ ProcRRSelectInput (ClientPtr client) CompareTimeStamps (pTimes->configTime, pScrPriv->lastConfigTime) != 0) { - RRDeliverScreenEvent (client, pWin, pScreen); + if (pRREvent->mask & RRScreenChangeNotifyMask) + { + RRDeliverScreenEvent (client, pWin, pScreen); + } + + if (pRREvent->mask & RRCrtcChangeNotifyMask) + { + int i; + + for (i = 0; i < pScrPriv->numCrtcs; i++) + { + RRDeliverCrtcEvent (client, pWin, pScrPriv->crtcs[i]); + } + } + + if (pRREvent->mask & RROutputChangeNotifyMask) + { + int i; + + for (i = 0; i < pScrPriv->numOutputs; i++) + { + RRDeliverOutputEvent (client, pWin, pScrPriv->outputs[i]); + } + } + + /* We don't check for RROutputPropertyNotifyMask, as randrproto.txt doesn't + * say if there ought to be notifications of changes to output properties + * if those changes occurred before the time RRSelectInput is called. + */ } } } diff --git a/xorg-server/render/render.c b/xorg-server/render/render.c index c5da6d78f..ebb1d630a 100644 --- a/xorg-server/render/render.c +++ b/xorg-server/render/render.c @@ -1705,11 +1705,17 @@ ProcRenderCreateCursor (ClientPtr client) GetColor(twocolor[1], 0), &pCursor, client, stuff->cid); if (rc != Success) - return rc; - if (!AddResource(stuff->cid, RT_CURSOR, (pointer)pCursor)) - return BadAlloc; + goto bail; + if (!AddResource(stuff->cid, RT_CURSOR, (pointer)pCursor)) { + rc = BadAlloc; + goto bail; + } return Success; +bail: + free(srcbits); + free(mskbits); + return rc; } static int diff --git a/xorg-server/xkeyboard-config/rules/compat/variantsMapping.lst b/xorg-server/xkeyboard-config/rules/compat/variantsMapping.lst index be2a2bc40..d88336fce 100644 --- a/xorg-server/xkeyboard-config/rules/compat/variantsMapping.lst +++ b/xorg-server/xkeyboard-config/rules/compat/variantsMapping.lst @@ -13,7 +13,6 @@ guj basic in guj gur basic in guru ie laptop ie basic ie CloGaelachLaptop ie CloGaelach -il si1452 ie basic in urd in urd-phonetic iu basic ca ike lo basic la basic diff --git a/xorg-server/xkeyboard-config/symbols/hu b/xorg-server/xkeyboard-config/symbols/hu index 16631b7ad..21913a330 100644 --- a/xorg-server/xkeyboard-config/symbols/hu +++ b/xorg-server/xkeyboard-config/symbols/hu @@ -425,7 +425,7 @@ xkb_symbols "def_common" { key <AB06> { [ n, N, braceright ] }; key <AB07> { [ m, M, less ] }; key <AB08> { [ comma, question, semicolon ] }; - key <AB09> { [ period, colon, ellipsis ] }; + key <AB09> { [ period, colon, greater ] }; key <AB10> { [ minus, underscore, asterisk ] }; }; |