diff options
Diffstat (limited to 'mesalib/src')
23 files changed, 1799 insertions, 1354 deletions
diff --git a/mesalib/src/gallium/auxiliary/util/u_pstipple.c b/mesalib/src/gallium/auxiliary/util/u_pstipple.c index 27f72e967..ac0df8c1a 100644 --- a/mesalib/src/gallium/auxiliary/util/u_pstipple.c +++ b/mesalib/src/gallium/auxiliary/util/u_pstipple.c @@ -1,434 +1,457 @@ -/**************************************************************************
- *
- * Copyright 2008 Tungsten Graphics, Inc., Cedar Park, Texas.
- * Copyright 2010 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, sub license, and/or sell copies of the Software, and to
- * permit persons to whom the Software is furnished to do so, subject to
- * the following conditions:
- *
- * The above copyright notice and this permission notice (including the
- * next paragraph) shall be included in all copies or substantial portions
- * of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
- * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
- * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT.
- * IN NO EVENT SHALL TUNGSTEN GRAPHICS AND/OR ITS SUPPLIERS BE LIABLE FOR
- * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
- * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
- * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
- *
- **************************************************************************/
-
-/**
- * Polygon stipple helper module. Drivers/GPUs which don't support polygon
- * stipple natively can use this module to simulate it.
- *
- * Basically, modify fragment shader to sample the 32x32 stipple pattern
- * texture and do a fragment kill for the 'off' bits.
- *
- * This was originally a 'draw' module stage, but since we don't need
- * vertex window coords or anything, it can be a stand-alone utility module.
- *
- * Authors: Brian Paul
- */
-
-
-#include "pipe/p_context.h"
-#include "pipe/p_defines.h"
-#include "pipe/p_shader_tokens.h"
-#include "util/u_inlines.h"
-
-#include "util/u_format.h"
-#include "util/u_memory.h"
-#include "util/u_pstipple.h"
-#include "util/u_sampler.h"
-
-#include "tgsi/tgsi_transform.h"
-#include "tgsi/tgsi_dump.h"
-
-/** Approx number of new tokens for instructions in pstip_transform_inst() */
-#define NUM_NEW_TOKENS 50
-
-
-static void
-util_pstipple_update_stipple_texture(struct pipe_context *pipe,
- struct pipe_resource *tex,
- const uint32_t pattern[32])
-{
- static const uint bit31 = 1 << 31;
- struct pipe_transfer *transfer;
- ubyte *data;
- int i, j;
-
- /* map texture memory */
- transfer = pipe_get_transfer(pipe, tex, 0, 0,
- PIPE_TRANSFER_WRITE, 0, 0, 32, 32);
- data = pipe->transfer_map(pipe, transfer);
-
- /*
- * Load alpha texture.
- * Note: 0 means keep the fragment, 255 means kill it.
- * We'll negate the texel value and use KILP which kills if value
- * is negative.
- */
- for (i = 0; i < 32; i++) {
- for (j = 0; j < 32; j++) {
- if (pattern[i] & (bit31 >> j)) {
- /* fragment "on" */
- data[i * transfer->stride + j] = 0;
- }
- else {
- /* fragment "off" */
- data[i * transfer->stride + j] = 255;
- }
- }
- }
-
- /* unmap */
- pipe->transfer_unmap(pipe, transfer);
- pipe->transfer_destroy(pipe, transfer);
-}
-
-
-/**
- * Create a 32x32 alpha8 texture that encodes the given stipple pattern.
- */
-struct pipe_resource *
-util_pstipple_create_stipple_texture(struct pipe_context *pipe,
- const uint32_t pattern[32])
-{
- struct pipe_screen *screen = pipe->screen;
- struct pipe_resource templat, *tex;
-
- memset(&templat, 0, sizeof(templat));
- templat.target = PIPE_TEXTURE_2D;
- templat.format = PIPE_FORMAT_A8_UNORM;
- templat.last_level = 0;
- templat.width0 = 32;
- templat.height0 = 32;
- templat.depth0 = 1;
- templat.array_size = 1;
- templat.bind = PIPE_BIND_SAMPLER_VIEW;
-
- tex = screen->resource_create(screen, &templat);
-
- if (tex)
- util_pstipple_update_stipple_texture(pipe, tex, pattern);
-
- return tex;
-}
-
-
-/**
- * Create sampler view to sample the stipple texture.
- */
-struct pipe_sampler_view *
-util_pstipple_create_sampler_view(struct pipe_context *pipe,
- struct pipe_resource *tex)
-{
- struct pipe_sampler_view templat, *sv;
-
- u_sampler_view_default_template(&templat, tex, tex->format);
- sv = pipe->create_sampler_view(pipe, tex, &templat);
-
- return sv;
-}
-
-
-/**
- * Create the sampler CSO that'll be used for stippling.
- */
-void *
-util_pstipple_create_sampler(struct pipe_context *pipe)
-{
- struct pipe_sampler_state templat;
- void *s;
-
- memset(&templat, 0, sizeof(templat));
- templat.wrap_s = PIPE_TEX_WRAP_REPEAT;
- templat.wrap_t = PIPE_TEX_WRAP_REPEAT;
- templat.wrap_r = PIPE_TEX_WRAP_REPEAT;
- templat.min_mip_filter = PIPE_TEX_MIPFILTER_NONE;
- templat.min_img_filter = PIPE_TEX_FILTER_NEAREST;
- templat.mag_img_filter = PIPE_TEX_FILTER_NEAREST;
- templat.normalized_coords = 1;
- templat.min_lod = 0.0f;
- templat.max_lod = 0.0f;
-
- s = pipe->create_sampler_state(pipe, &templat);
- return s;
-}
-
-
-
-/**
- * Subclass of tgsi_transform_context, used for transforming the
- * user's fragment shader to add the extra texture sample and fragment kill
- * instructions.
- */
-struct pstip_transform_context {
- struct tgsi_transform_context base;
- uint tempsUsed; /**< bitmask */
- int wincoordInput;
- int maxInput;
- uint samplersUsed; /**< bitfield of samplers used */
- int freeSampler; /** an available sampler for the pstipple */
- int texTemp; /**< temp registers */
- int numImmed;
- boolean firstInstruction;
-};
-
-
-/**
- * TGSI declaration transform callback.
- * Look for a free sampler, a free input attrib, and two free temp regs.
- */
-static void
-pstip_transform_decl(struct tgsi_transform_context *ctx,
- struct tgsi_full_declaration *decl)
-{
- struct pstip_transform_context *pctx =
- (struct pstip_transform_context *) ctx;
-
- if (decl->Declaration.File == TGSI_FILE_SAMPLER) {
- uint i;
- for (i = decl->Range.First;
- i <= decl->Range.Last; i++) {
- pctx->samplersUsed |= 1 << i;
- }
- }
- else if (decl->Declaration.File == TGSI_FILE_INPUT) {
- pctx->maxInput = MAX2(pctx->maxInput, (int) decl->Range.Last);
- if (decl->Semantic.Name == TGSI_SEMANTIC_POSITION)
- pctx->wincoordInput = (int) decl->Range.First;
- }
- else if (decl->Declaration.File == TGSI_FILE_TEMPORARY) {
- uint i;
- for (i = decl->Range.First;
- i <= decl->Range.Last; i++) {
- pctx->tempsUsed |= (1 << i);
- }
- }
-
- ctx->emit_declaration(ctx, decl);
-}
-
-
-static void
-pstip_transform_immed(struct tgsi_transform_context *ctx,
- struct tgsi_full_immediate *immed)
-{
- struct pstip_transform_context *pctx =
- (struct pstip_transform_context *) ctx;
- pctx->numImmed++;
-}
-
-
-/**
- * Find the lowest zero bit in the given word, or -1 if bitfield is all ones.
- */
-static int
-free_bit(uint bitfield)
-{
- return ffs(~bitfield) - 1;
-}
-
-
-/**
- * TGSI instruction transform callback.
- * Replace writes to result.color w/ a temp reg.
- * Upon END instruction, insert texture sampling code for antialiasing.
- */
-static void
-pstip_transform_inst(struct tgsi_transform_context *ctx,
- struct tgsi_full_instruction *inst)
-{
- struct pstip_transform_context *pctx =
- (struct pstip_transform_context *) ctx;
-
- if (pctx->firstInstruction) {
- /* emit our new declarations before the first instruction */
-
- struct tgsi_full_declaration decl;
- struct tgsi_full_instruction newInst;
- uint i;
- int wincoordInput;
-
- /* find free sampler */
- pctx->freeSampler = free_bit(pctx->samplersUsed);
- if (pctx->freeSampler >= PIPE_MAX_SAMPLERS)
- pctx->freeSampler = PIPE_MAX_SAMPLERS - 1;
-
- if (pctx->wincoordInput < 0)
- wincoordInput = pctx->maxInput + 1;
- else
- wincoordInput = pctx->wincoordInput;
-
- /* find one free temp reg */
- for (i = 0; i < 32; i++) {
- if ((pctx->tempsUsed & (1 << i)) == 0) {
- /* found a free temp */
- if (pctx->texTemp < 0)
- pctx->texTemp = i;
- else
- break;
- }
- }
- assert(pctx->texTemp >= 0);
-
- if (pctx->wincoordInput < 0) {
- /* declare new position input reg */
- decl = tgsi_default_full_declaration();
- decl.Declaration.File = TGSI_FILE_INPUT;
- decl.Declaration.Interpolate = TGSI_INTERPOLATE_LINEAR;
- decl.Declaration.Semantic = 1;
- decl.Semantic.Name = TGSI_SEMANTIC_POSITION;
- decl.Semantic.Index = 0;
- decl.Range.First =
- decl.Range.Last = wincoordInput;
- ctx->emit_declaration(ctx, &decl);
- }
-
- /* declare new sampler */
- decl = tgsi_default_full_declaration();
- decl.Declaration.File = TGSI_FILE_SAMPLER;
- decl.Range.First =
- decl.Range.Last = pctx->freeSampler;
- ctx->emit_declaration(ctx, &decl);
-
- /* declare new temp regs */
- decl = tgsi_default_full_declaration();
- decl.Declaration.File = TGSI_FILE_TEMPORARY;
- decl.Range.First =
- decl.Range.Last = pctx->texTemp;
- ctx->emit_declaration(ctx, &decl);
-
- /* emit immediate = {1/32, 1/32, 1, 1}
- * The index/position of this immediate will be pctx->numImmed
- */
- {
- static const float value[4] = { 1.0/32, 1.0/32, 1.0, 1.0 };
- struct tgsi_full_immediate immed;
- uint size = 4;
- immed = tgsi_default_full_immediate();
- immed.Immediate.NrTokens = 1 + size; /* one for the token itself */
- immed.u[0].Float = value[0];
- immed.u[1].Float = value[1];
- immed.u[2].Float = value[2];
- immed.u[3].Float = value[3];
- ctx->emit_immediate(ctx, &immed);
- }
-
- pctx->firstInstruction = FALSE;
-
-
- /*
- * Insert new MUL/TEX/KILP instructions at start of program
- * Take gl_FragCoord, divide by 32 (stipple size), sample the
- * texture and kill fragment if needed.
- *
- * We'd like to use non-normalized texcoords to index into a RECT
- * texture, but we can only use REPEAT wrap mode with normalized
- * texcoords. Darn.
- */
-
- /* XXX invert wincoord if origin isn't lower-left... */
-
- /* MUL texTemp, INPUT[wincoord], 1/32; */
- newInst = tgsi_default_full_instruction();
- newInst.Instruction.Opcode = TGSI_OPCODE_MUL;
- newInst.Instruction.NumDstRegs = 1;
- newInst.Dst[0].Register.File = TGSI_FILE_TEMPORARY;
- newInst.Dst[0].Register.Index = pctx->texTemp;
- newInst.Instruction.NumSrcRegs = 2;
- newInst.Src[0].Register.File = TGSI_FILE_INPUT;
- newInst.Src[0].Register.Index = wincoordInput;
- newInst.Src[1].Register.File = TGSI_FILE_IMMEDIATE;
- newInst.Src[1].Register.Index = pctx->numImmed;
- ctx->emit_instruction(ctx, &newInst);
-
- /* TEX texTemp, texTemp, sampler; */
- newInst = tgsi_default_full_instruction();
- newInst.Instruction.Opcode = TGSI_OPCODE_TEX;
- newInst.Instruction.NumDstRegs = 1;
- newInst.Dst[0].Register.File = TGSI_FILE_TEMPORARY;
- newInst.Dst[0].Register.Index = pctx->texTemp;
- newInst.Instruction.NumSrcRegs = 2;
- newInst.Instruction.Texture = TRUE;
- newInst.Texture.Texture = TGSI_TEXTURE_2D;
- newInst.Src[0].Register.File = TGSI_FILE_TEMPORARY;
- newInst.Src[0].Register.Index = pctx->texTemp;
- newInst.Src[1].Register.File = TGSI_FILE_SAMPLER;
- newInst.Src[1].Register.Index = pctx->freeSampler;
- ctx->emit_instruction(ctx, &newInst);
-
- /* KIL -texTemp; # if -texTemp < 0, KILL fragment */
- newInst = tgsi_default_full_instruction();
- newInst.Instruction.Opcode = TGSI_OPCODE_KIL;
- newInst.Instruction.NumDstRegs = 0;
- newInst.Instruction.NumSrcRegs = 1;
- newInst.Src[0].Register.File = TGSI_FILE_TEMPORARY;
- newInst.Src[0].Register.Index = pctx->texTemp;
- newInst.Src[0].Register.Negate = 1;
- ctx->emit_instruction(ctx, &newInst);
- }
-
- /* emit this instruction */
- ctx->emit_instruction(ctx, inst);
-}
-
-
-/**
- * Given a fragment shader, return a new fragment shader which
- * samples a stipple texture and executes KILL.
- */
-struct pipe_shader_state *
-util_pstipple_create_fragment_shader(struct pipe_context *pipe,
- struct pipe_shader_state *fs,
- unsigned *samplerUnitOut)
-{
- struct pipe_shader_state *new_fs;
- struct pstip_transform_context transform;
- const uint newLen = tgsi_num_tokens(fs->tokens) + NUM_NEW_TOKENS;
-
- new_fs = MALLOC(sizeof(*new_fs));
- if (!new_fs)
- return NULL;
-
- new_fs->tokens = tgsi_alloc_tokens(newLen);
- if (!new_fs->tokens) {
- FREE(new_fs);
- return NULL;
- }
-
- memset(&transform, 0, sizeof(transform));
- transform.wincoordInput = -1;
- transform.maxInput = -1;
- transform.texTemp = -1;
- transform.firstInstruction = TRUE;
- transform.base.transform_instruction = pstip_transform_inst;
- transform.base.transform_declaration = pstip_transform_decl;
- transform.base.transform_immediate = pstip_transform_immed;
-
- tgsi_transform_shader(fs->tokens,
- (struct tgsi_token *) new_fs->tokens,
- newLen, &transform.base);
-
-#if 0 /* DEBUG */
- tgsi_dump(fs->tokens, 0);
- tgsi_dump(pstip_fs.tokens, 0);
-#endif
-
- assert(transform.freeSampler < PIPE_MAX_SAMPLERS);
- *samplerUnitOut = transform.freeSampler;
-
- return new_fs;
-}
-
+/************************************************************************** + * + * Copyright 2008 Tungsten Graphics, Inc., Cedar Park, Texas. + * Copyright 2010 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, sub license, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice (including the + * next paragraph) shall be included in all copies or substantial portions + * of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. + * IN NO EVENT SHALL TUNGSTEN GRAPHICS AND/OR ITS SUPPLIERS BE LIABLE FOR + * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, + * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE + * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + **************************************************************************/ + +/** + * Polygon stipple helper module. Drivers/GPUs which don't support polygon + * stipple natively can use this module to simulate it. + * + * Basically, modify fragment shader to sample the 32x32 stipple pattern + * texture and do a fragment kill for the 'off' bits. + * + * This was originally a 'draw' module stage, but since we don't need + * vertex window coords or anything, it can be a stand-alone utility module. + * + * Authors: Brian Paul + */ + + +#include "pipe/p_context.h" +#include "pipe/p_defines.h" +#include "pipe/p_shader_tokens.h" +#include "util/u_inlines.h" + +#include "util/u_format.h" +#include "util/u_memory.h" +#include "util/u_pstipple.h" +#include "util/u_sampler.h" + +#include "tgsi/tgsi_transform.h" +#include "tgsi/tgsi_dump.h" +#include "tgsi/tgsi_scan.h" + +/** Approx number of new tokens for instructions in pstip_transform_inst() */ +#define NUM_NEW_TOKENS 50 + + +static void +util_pstipple_update_stipple_texture(struct pipe_context *pipe, + struct pipe_resource *tex, + const uint32_t pattern[32]) +{ + static const uint bit31 = 1 << 31; + struct pipe_transfer *transfer; + ubyte *data; + int i, j; + + /* map texture memory */ + transfer = pipe_get_transfer(pipe, tex, 0, 0, + PIPE_TRANSFER_WRITE, 0, 0, 32, 32); + data = pipe->transfer_map(pipe, transfer); + + /* + * Load alpha texture. + * Note: 0 means keep the fragment, 255 means kill it. + * We'll negate the texel value and use KILP which kills if value + * is negative. + */ + for (i = 0; i < 32; i++) { + for (j = 0; j < 32; j++) { + if (pattern[i] & (bit31 >> j)) { + /* fragment "on" */ + data[i * transfer->stride + j] = 0; + } + else { + /* fragment "off" */ + data[i * transfer->stride + j] = 255; + } + } + } + + /* unmap */ + pipe->transfer_unmap(pipe, transfer); + pipe->transfer_destroy(pipe, transfer); +} + + +/** + * Create a 32x32 alpha8 texture that encodes the given stipple pattern. + */ +struct pipe_resource * +util_pstipple_create_stipple_texture(struct pipe_context *pipe, + const uint32_t pattern[32]) +{ + struct pipe_screen *screen = pipe->screen; + struct pipe_resource templat, *tex; + + memset(&templat, 0, sizeof(templat)); + templat.target = PIPE_TEXTURE_2D; + templat.format = PIPE_FORMAT_A8_UNORM; + templat.last_level = 0; + templat.width0 = 32; + templat.height0 = 32; + templat.depth0 = 1; + templat.array_size = 1; + templat.bind = PIPE_BIND_SAMPLER_VIEW; + + tex = screen->resource_create(screen, &templat); + + if (tex) + util_pstipple_update_stipple_texture(pipe, tex, pattern); + + return tex; +} + + +/** + * Create sampler view to sample the stipple texture. + */ +struct pipe_sampler_view * +util_pstipple_create_sampler_view(struct pipe_context *pipe, + struct pipe_resource *tex) +{ + struct pipe_sampler_view templat, *sv; + + u_sampler_view_default_template(&templat, tex, tex->format); + sv = pipe->create_sampler_view(pipe, tex, &templat); + + return sv; +} + + +/** + * Create the sampler CSO that'll be used for stippling. + */ +void * +util_pstipple_create_sampler(struct pipe_context *pipe) +{ + struct pipe_sampler_state templat; + void *s; + + memset(&templat, 0, sizeof(templat)); + templat.wrap_s = PIPE_TEX_WRAP_REPEAT; + templat.wrap_t = PIPE_TEX_WRAP_REPEAT; + templat.wrap_r = PIPE_TEX_WRAP_REPEAT; + templat.min_mip_filter = PIPE_TEX_MIPFILTER_NONE; + templat.min_img_filter = PIPE_TEX_FILTER_NEAREST; + templat.mag_img_filter = PIPE_TEX_FILTER_NEAREST; + templat.normalized_coords = 1; + templat.min_lod = 0.0f; + templat.max_lod = 0.0f; + + s = pipe->create_sampler_state(pipe, &templat); + return s; +} + + + +/** + * Subclass of tgsi_transform_context, used for transforming the + * user's fragment shader to add the extra texture sample and fragment kill + * instructions. + */ +struct pstip_transform_context { + struct tgsi_transform_context base; + struct tgsi_shader_info info; + uint tempsUsed; /**< bitmask */ + int wincoordInput; + int maxInput; + uint samplersUsed; /**< bitfield of samplers used */ + int freeSampler; /** an available sampler for the pstipple */ + int texTemp; /**< temp registers */ + int numImmed; + boolean firstInstruction; + uint coordOrigin; +}; + + +/** + * TGSI declaration transform callback. + * Track samplers used, temps used, inputs used. + */ +static void +pstip_transform_decl(struct tgsi_transform_context *ctx, + struct tgsi_full_declaration *decl) +{ + struct pstip_transform_context *pctx = + (struct pstip_transform_context *) ctx; + + /* XXX we can use tgsi_shader_info instead of some of this */ + + if (decl->Declaration.File == TGSI_FILE_SAMPLER) { + uint i; + for (i = decl->Range.First; i <= decl->Range.Last; i++) { + pctx->samplersUsed |= 1 << i; + } + } + else if (decl->Declaration.File == TGSI_FILE_INPUT) { + pctx->maxInput = MAX2(pctx->maxInput, (int) decl->Range.Last); + if (decl->Semantic.Name == TGSI_SEMANTIC_POSITION) + pctx->wincoordInput = (int) decl->Range.First; + } + else if (decl->Declaration.File == TGSI_FILE_TEMPORARY) { + uint i; + for (i = decl->Range.First; i <= decl->Range.Last; i++) { + pctx->tempsUsed |= (1 << i); + } + } + + ctx->emit_declaration(ctx, decl); +} + + +static void +pstip_transform_immed(struct tgsi_transform_context *ctx, + struct tgsi_full_immediate *immed) +{ + struct pstip_transform_context *pctx = + (struct pstip_transform_context *) ctx; + pctx->numImmed++; +} + + +/** + * Find the lowest zero bit in the given word, or -1 if bitfield is all ones. + */ +static int +free_bit(uint bitfield) +{ + return ffs(~bitfield) - 1; +} + + +/** + * TGSI instruction transform callback. + * Before the first instruction, insert our new code to sample the + * stipple texture (using the fragment coord register) then kill the + * fragment if the stipple texture bit is off. + * + * Insert: + * declare new registers + * MUL texTemp, INPUT[wincoord], 1/32; + * TEX texTemp, texTemp, sampler; + * KIL -texTemp; # if -texTemp < 0, KILL fragment + * [...original code...] + */ +static void +pstip_transform_inst(struct tgsi_transform_context *ctx, + struct tgsi_full_instruction *inst) +{ + struct pstip_transform_context *pctx = + (struct pstip_transform_context *) ctx; + + if (pctx->firstInstruction) { + /* emit our new declarations before the first instruction */ + + struct tgsi_full_declaration decl; + struct tgsi_full_instruction newInst; + uint i; + int wincoordInput; + + /* find free texture sampler */ + pctx->freeSampler = free_bit(pctx->samplersUsed); + if (pctx->freeSampler >= PIPE_MAX_SAMPLERS) + pctx->freeSampler = PIPE_MAX_SAMPLERS - 1; + + if (pctx->wincoordInput < 0) + wincoordInput = pctx->maxInput + 1; + else + wincoordInput = pctx->wincoordInput; + + /* find one free temp register */ + for (i = 0; i < 32; i++) { + if ((pctx->tempsUsed & (1 << i)) == 0) { + /* found a free temp */ + if (pctx->texTemp < 0) + pctx->texTemp = i; + else + break; + } + } + assert(pctx->texTemp >= 0); + + if (pctx->wincoordInput < 0) { + /* declare new position input reg */ + decl = tgsi_default_full_declaration(); + decl.Declaration.File = TGSI_FILE_INPUT; + decl.Declaration.Interpolate = TGSI_INTERPOLATE_LINEAR; + decl.Declaration.Semantic = 1; + decl.Semantic.Name = TGSI_SEMANTIC_POSITION; + decl.Semantic.Index = 0; + decl.Range.First = + decl.Range.Last = wincoordInput; + ctx->emit_declaration(ctx, &decl); + } + + /* declare new sampler */ + decl = tgsi_default_full_declaration(); + decl.Declaration.File = TGSI_FILE_SAMPLER; + decl.Range.First = + decl.Range.Last = pctx->freeSampler; + ctx->emit_declaration(ctx, &decl); + + /* declare new temp regs */ + decl = tgsi_default_full_declaration(); + decl.Declaration.File = TGSI_FILE_TEMPORARY; + decl.Range.First = + decl.Range.Last = pctx->texTemp; + ctx->emit_declaration(ctx, &decl); + + /* emit immediate = {1/32, 1/32, 1, 1} + * The index/position of this immediate will be pctx->numImmed + */ + { + static const float value[4] = { 1.0/32, 1.0/32, 1.0, 1.0 }; + struct tgsi_full_immediate immed; + uint size = 4; + immed = tgsi_default_full_immediate(); + immed.Immediate.NrTokens = 1 + size; /* one for the token itself */ + immed.u[0].Float = value[0]; + immed.u[1].Float = value[1]; + immed.u[2].Float = value[2]; + immed.u[3].Float = value[3]; + ctx->emit_immediate(ctx, &immed); + } + + pctx->firstInstruction = FALSE; + + + /* + * Insert new MUL/TEX/KILP instructions at start of program + * Take gl_FragCoord, divide by 32 (stipple size), sample the + * texture and kill fragment if needed. + * + * We'd like to use non-normalized texcoords to index into a RECT + * texture, but we can only use REPEAT wrap mode with normalized + * texcoords. Darn. + */ + + /* XXX invert wincoord if origin isn't lower-left... */ + + /* MUL texTemp, INPUT[wincoord], 1/32; */ + newInst = tgsi_default_full_instruction(); + newInst.Instruction.Opcode = TGSI_OPCODE_MUL; + newInst.Instruction.NumDstRegs = 1; + newInst.Dst[0].Register.File = TGSI_FILE_TEMPORARY; + newInst.Dst[0].Register.Index = pctx->texTemp; + newInst.Instruction.NumSrcRegs = 2; + newInst.Src[0].Register.File = TGSI_FILE_INPUT; + newInst.Src[0].Register.Index = wincoordInput; + newInst.Src[1].Register.File = TGSI_FILE_IMMEDIATE; + newInst.Src[1].Register.Index = pctx->numImmed; + ctx->emit_instruction(ctx, &newInst); + + /* TEX texTemp, texTemp, sampler; */ + newInst = tgsi_default_full_instruction(); + newInst.Instruction.Opcode = TGSI_OPCODE_TEX; + newInst.Instruction.NumDstRegs = 1; + newInst.Dst[0].Register.File = TGSI_FILE_TEMPORARY; + newInst.Dst[0].Register.Index = pctx->texTemp; + newInst.Instruction.NumSrcRegs = 2; + newInst.Instruction.Texture = TRUE; + newInst.Texture.Texture = TGSI_TEXTURE_2D; + newInst.Src[0].Register.File = TGSI_FILE_TEMPORARY; + newInst.Src[0].Register.Index = pctx->texTemp; + newInst.Src[1].Register.File = TGSI_FILE_SAMPLER; + newInst.Src[1].Register.Index = pctx->freeSampler; + ctx->emit_instruction(ctx, &newInst); + + /* KIL -texTemp; # if -texTemp < 0, KILL fragment */ + newInst = tgsi_default_full_instruction(); + newInst.Instruction.Opcode = TGSI_OPCODE_KIL; + newInst.Instruction.NumDstRegs = 0; + newInst.Instruction.NumSrcRegs = 1; + newInst.Src[0].Register.File = TGSI_FILE_TEMPORARY; + newInst.Src[0].Register.Index = pctx->texTemp; + newInst.Src[0].Register.Negate = 1; + ctx->emit_instruction(ctx, &newInst); + } + + /* emit this instruction */ + ctx->emit_instruction(ctx, inst); +} + + +/** + * Given a fragment shader, return a new fragment shader which + * samples a stipple texture and executes KILL. + */ +struct pipe_shader_state * +util_pstipple_create_fragment_shader(struct pipe_context *pipe, + struct pipe_shader_state *fs, + unsigned *samplerUnitOut) +{ + struct pipe_shader_state *new_fs; + struct pstip_transform_context transform; + const uint newLen = tgsi_num_tokens(fs->tokens) + NUM_NEW_TOKENS; + unsigned i; + + new_fs = MALLOC(sizeof(*new_fs)); + if (!new_fs) + return NULL; + + new_fs->tokens = tgsi_alloc_tokens(newLen); + if (!new_fs->tokens) { + FREE(new_fs); + return NULL; + } + + /* Setup shader transformation info/context. + */ + memset(&transform, 0, sizeof(transform)); + transform.wincoordInput = -1; + transform.maxInput = -1; + transform.texTemp = -1; + transform.firstInstruction = TRUE; + transform.coordOrigin = TGSI_FS_COORD_ORIGIN_UPPER_LEFT; + transform.base.transform_instruction = pstip_transform_inst; + transform.base.transform_declaration = pstip_transform_decl; + transform.base.transform_immediate = pstip_transform_immed; + + tgsi_scan_shader(fs->tokens, &transform.info); + + /* find fragment coordinate origin property */ + for (i = 0; i < transform.info.num_properties; i++) { + if (transform.info.properties[i].name == TGSI_PROPERTY_FS_COORD_ORIGIN) + transform.coordOrigin = transform.info.properties[i].data[0]; + } + + tgsi_transform_shader(fs->tokens, + (struct tgsi_token *) new_fs->tokens, + newLen, &transform.base); + +#if 0 /* DEBUG */ + tgsi_dump(fs->tokens, 0); + tgsi_dump(new_fs->tokens, 0); +#endif + + assert(transform.freeSampler < PIPE_MAX_SAMPLERS); + *samplerUnitOut = transform.freeSampler; + + return new_fs; +} + diff --git a/mesalib/src/gallium/auxiliary/util/u_vbuf_mgr.c b/mesalib/src/gallium/auxiliary/util/u_vbuf_mgr.c index a2709f855..1b9375209 100644 --- a/mesalib/src/gallium/auxiliary/util/u_vbuf_mgr.c +++ b/mesalib/src/gallium/auxiliary/util/u_vbuf_mgr.c @@ -79,6 +79,8 @@ struct u_vbuf_mgr_priv { void *saved_ve, *fallback_ve;
boolean ve_binding_lock;
+ unsigned saved_buffer_offset[PIPE_MAX_ATTRIBS];
+
boolean any_user_vbs;
boolean incompatible_vb_layout;
};
@@ -488,6 +490,7 @@ void u_vbuf_mgr_set_vertex_buffers(struct u_vbuf_mgr *mgrb, pipe_resource_reference(&mgr->b.vertex_buffer[i].buffer, vb->buffer);
pipe_resource_reference(&mgr->b.real_vertex_buffer[i], NULL);
+ mgr->saved_buffer_offset[i] = vb->buffer_offset;
if (!vb->buffer) {
continue;
@@ -647,6 +650,13 @@ u_vbuf_mgr_draw_begin(struct u_vbuf_mgr *mgrb, void u_vbuf_mgr_draw_end(struct u_vbuf_mgr *mgrb)
{
struct u_vbuf_mgr_priv *mgr = (struct u_vbuf_mgr_priv*)mgrb;
+ unsigned i;
+
+ /* buffer offsets were modified in u_vbuf_upload_buffers */
+ if (mgr->any_user_vbs) {
+ for (i = 0; i < mgr->b.nr_vertex_buffers; i++)
+ mgr->b.vertex_buffer[i].buffer_offset = mgr->saved_buffer_offset[i];
+ }
if (mgr->fallback_ve) {
u_vbuf_translate_end(mgr);
diff --git a/mesalib/src/glsl/Makefile b/mesalib/src/glsl/Makefile index e0776c1b5..d1422c2a4 100644 --- a/mesalib/src/glsl/Makefile +++ b/mesalib/src/glsl/Makefile @@ -39,6 +39,7 @@ CXX_SOURCES = \ ir.cpp \ ir_expression_flattening.cpp \ ir_function_can_inline.cpp \ + ir_function_detect_recursion.cpp \ ir_function.cpp \ ir_hierarchical_visitor.cpp \ ir_hv_accept.cpp \ diff --git a/mesalib/src/glsl/SConscript b/mesalib/src/glsl/SConscript index 1441cc74b..ea104abb8 100644 --- a/mesalib/src/glsl/SConscript +++ b/mesalib/src/glsl/SConscript @@ -50,6 +50,7 @@ glsl_sources = [ 'ir.cpp', 'ir_expression_flattening.cpp', 'ir_function_can_inline.cpp', + 'ir_function_detect_recursion.cpp', 'ir_function.cpp', 'ir_hierarchical_visitor.cpp', 'ir_hv_accept.cpp', diff --git a/mesalib/src/glsl/ast_function.cpp b/mesalib/src/glsl/ast_function.cpp index c35e06089..fad069135 100644 --- a/mesalib/src/glsl/ast_function.cpp +++ b/mesalib/src/glsl/ast_function.cpp @@ -62,8 +62,10 @@ process_parameters(exec_list *instructions, exec_list *actual_parameters, *
* \param return_type Return type of the function. May be \c NULL.
* \param name Name of the function.
- * \param parameters Parameter list for the function. This may be either a
- * formal or actual parameter list. Only the type is used.
+ * \param parameters List of \c ir_instruction nodes representing the
+ * parameter list for the function. This may be either a
+ * formal (\c ir_variable) or actual (\c ir_rvalue)
+ * parameter list. Only the type is used.
*
* \return
* A ralloced string representing the prototype of the function.
diff --git a/mesalib/src/glsl/ast_to_hir.cpp b/mesalib/src/glsl/ast_to_hir.cpp index 546c18c35..e1cecc11b 100644 --- a/mesalib/src/glsl/ast_to_hir.cpp +++ b/mesalib/src/glsl/ast_to_hir.cpp @@ -83,6 +83,8 @@ _mesa_ast_to_hir(exec_list *instructions, struct _mesa_glsl_parse_state *state) foreach_list_typed (ast_node, ast, link, & state->translation_unit)
ast->hir(instructions, state);
+
+ detect_recursion_unlinked(state, instructions);
}
@@ -2704,6 +2706,17 @@ ast_declarator_list::hir(exec_list *instructions, : "and integer");
}
+ /* From page 17 (page 23 of the PDF) of the GLSL 1.20 spec:
+ *
+ * "[Sampler types] can only be declared as function
+ * parameters or uniform variables (see Section 4.3.5
+ * "Uniform")".
+ */
+ if (var_type->contains_sampler() &&
+ !this->type->qualifier.flags.q.uniform) {
+ _mesa_glsl_error(&loc, state, "samplers must be declared uniform");
+ }
+
/* Process the initializer and add its instructions to a temporary
* list. This list will be added to the instruction stream (below) after
* the declaration is added. This is done because in some cases (such as
@@ -2864,6 +2877,18 @@ ast_parameter_declarator::hir(exec_list *instructions, */
apply_type_qualifier_to_variable(& this->type->qualifier, var, state, & loc);
+ /* From page 17 (page 23 of the PDF) of the GLSL 1.20 spec:
+ *
+ * "Samplers cannot be treated as l-values; hence cannot be used
+ * as out or inout function parameters, nor can they be assigned
+ * into."
+ */
+ if ((var->mode == ir_var_inout || var->mode == ir_var_out)
+ && type->contains_sampler()) {
+ _mesa_glsl_error(&loc, state, "out and inout parameters cannot contain samplers");
+ type = glsl_type::error_type;
+ }
+
instructions->push_tail(var);
/* Parameter declarations do not have r-values.
@@ -2992,6 +3017,18 @@ ast_function::hir(exec_list *instructions, "function `%s' return type has qualifiers", name);
}
+ /* From page 17 (page 23 of the PDF) of the GLSL 1.20 spec:
+ *
+ * "[Sampler types] can only be declared as function parameters
+ * or uniform variables (see Section 4.3.5 "Uniform")".
+ */
+ if (return_type->contains_sampler()) {
+ YYLTYPE loc = this->get_location();
+ _mesa_glsl_error(&loc, state,
+ "function `%s' return type can't contain a sampler",
+ name);
+ }
+
/* Verify that this function's signature either doesn't match a previously
* seen signature for a function with the same name, or, if a match is found,
* that the previously seen signature does not have an associated definition.
diff --git a/mesalib/src/glsl/glsl_types.cpp b/mesalib/src/glsl/glsl_types.cpp index ba862dfd6..978e9a398 100644 --- a/mesalib/src/glsl/glsl_types.cpp +++ b/mesalib/src/glsl/glsl_types.cpp @@ -111,6 +111,22 @@ add_types_to_symbol_table(glsl_symbol_table *symtab, }
}
+bool
+glsl_type::contains_sampler() const
+{
+ if (this->is_array()) {
+ return this->fields.array->contains_sampler();
+ } else if (this->is_record()) {
+ for (unsigned int i = 0; i < this->length; i++) {
+ if (this->fields.structure[i].type->contains_sampler())
+ return true;
+ }
+ return false;
+ } else {
+ return this->is_sampler();
+ }
+}
+
void
glsl_type::generate_100ES_types(glsl_symbol_table *symtab)
{
diff --git a/mesalib/src/glsl/glsl_types.h b/mesalib/src/glsl/glsl_types.h index e4c84c953..87f57e7c7 100644 --- a/mesalib/src/glsl/glsl_types.h +++ b/mesalib/src/glsl/glsl_types.h @@ -1,478 +1,484 @@ -/* -*- c++ -*- */
-/*
- * 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
-#ifndef GLSL_TYPES_H
-#define GLSL_TYPES_H
-
-#include <string.h>
-#include <assert.h>
-
-extern "C" {
-#include "GL/gl.h"
-}
-
-#include "ralloc.h"
-
-struct _mesa_glsl_parse_state;
-struct glsl_symbol_table;
-
-extern "C" void
-_mesa_glsl_initialize_types(struct _mesa_glsl_parse_state *state);
-
-extern "C" void
-_mesa_glsl_release_types(void);
-
-enum glsl_base_type {
- GLSL_TYPE_UINT = 0,
- GLSL_TYPE_INT,
- GLSL_TYPE_FLOAT,
- GLSL_TYPE_BOOL,
- GLSL_TYPE_SAMPLER,
- GLSL_TYPE_STRUCT,
- GLSL_TYPE_ARRAY,
- GLSL_TYPE_VOID,
- GLSL_TYPE_ERROR
-};
-
-enum glsl_sampler_dim {
- GLSL_SAMPLER_DIM_1D = 0,
- GLSL_SAMPLER_DIM_2D,
- GLSL_SAMPLER_DIM_3D,
- GLSL_SAMPLER_DIM_CUBE,
- GLSL_SAMPLER_DIM_RECT,
- GLSL_SAMPLER_DIM_BUF
-};
-
-
-struct glsl_type {
- GLenum gl_type;
- glsl_base_type base_type;
-
- unsigned sampler_dimensionality:3; /**< \see glsl_sampler_dim */
- unsigned sampler_shadow:1;
- unsigned sampler_array:1;
- unsigned sampler_type:2; /**< Type of data returned using this sampler.
- * only \c GLSL_TYPE_FLOAT, \c GLSL_TYPE_INT,
- * and \c GLSL_TYPE_UINT are valid.
- */
-
- /* Callers of this ralloc-based new need not call delete. It's
- * easier to just ralloc_free 'mem_ctx' (or any of its ancestors). */
- static void* operator new(size_t size)
- {
- if (glsl_type::mem_ctx == NULL) {
- glsl_type::mem_ctx = ralloc_context(NULL);
- assert(glsl_type::mem_ctx != NULL);
- }
-
- void *type;
-
- type = ralloc_size(glsl_type::mem_ctx, size);
- assert(type != NULL);
-
- return type;
- }
-
- /* If the user *does* call delete, that's OK, we will just
- * ralloc_free in that case. */
- static void operator delete(void *type)
- {
- ralloc_free(type);
- }
-
- /**
- * \name Vector and matrix element counts
- *
- * For scalars, each of these values will be 1. For non-numeric types
- * these will be 0.
- */
- /*@{*/
- unsigned vector_elements:3; /**< 1, 2, 3, or 4 vector elements. */
- unsigned matrix_columns:3; /**< 1, 2, 3, or 4 matrix columns. */
- /*@}*/
-
- /**
- * Name of the data type
- *
- * This may be \c NULL for anonymous structures, for arrays, or for
- * function types.
- */
- const char *name;
-
- /**
- * For \c GLSL_TYPE_ARRAY, this is the length of the array. For
- * \c GLSL_TYPE_STRUCT, it is the number of elements in the structure and
- * the number of values pointed to by \c fields.structure (below).
- */
- unsigned length;
-
- /**
- * Subtype of composite data types.
- */
- union {
- const struct glsl_type *array; /**< Type of array elements. */
- const struct glsl_type *parameters; /**< Parameters to function. */
- struct glsl_struct_field *structure; /**< List of struct fields. */
- } fields;
-
-
- /**
- * \name Pointers to various public type singletons
- */
- /*@{*/
- static const glsl_type *const error_type;
- static const glsl_type *const void_type;
- static const glsl_type *const int_type;
- static const glsl_type *const ivec4_type;
- static const glsl_type *const uint_type;
- static const glsl_type *const uvec2_type;
- static const glsl_type *const uvec3_type;
- static const glsl_type *const uvec4_type;
- static const glsl_type *const float_type;
- static const glsl_type *const vec2_type;
- static const glsl_type *const vec3_type;
- static const glsl_type *const vec4_type;
- static const glsl_type *const bool_type;
- static const glsl_type *const mat2_type;
- static const glsl_type *const mat2x3_type;
- static const glsl_type *const mat2x4_type;
- static const glsl_type *const mat3x2_type;
- static const glsl_type *const mat3_type;
- static const glsl_type *const mat3x4_type;
- static const glsl_type *const mat4x2_type;
- static const glsl_type *const mat4x3_type;
- static const glsl_type *const mat4_type;
- /*@}*/
-
-
- /**
- * For numeric and boolean derrived types returns the basic scalar type
- *
- * If the type is a numeric or boolean scalar, vector, or matrix type,
- * this function gets the scalar type of the individual components. For
- * all other types, including arrays of numeric or boolean types, the
- * error type is returned.
- */
- const glsl_type *get_base_type() const;
-
- /**
- * Query the type of elements in an array
- *
- * \return
- * Pointer to the type of elements in the array for array types, or \c NULL
- * for non-array types.
- */
- const glsl_type *element_type() const
- {
- return is_array() ? fields.array : NULL;
- }
-
- /**
- * Get the instance of a built-in scalar, vector, or matrix type
- */
- static const glsl_type *get_instance(unsigned base_type, unsigned rows,
- unsigned columns);
-
- /**
- * Get the instance of an array type
- */
- static const glsl_type *get_array_instance(const glsl_type *base,
- unsigned elements);
-
- /**
- * Get the instance of a record type
- */
- static const glsl_type *get_record_instance(const glsl_struct_field *fields,
- unsigned num_fields,
- const char *name);
-
- /**
- * Query the total number of scalars that make up a scalar, vector or matrix
- */
- unsigned components() const
- {
- return vector_elements * matrix_columns;
- }
-
- /**
- * Calculate the number of components slots required to hold this type
- *
- * This is used to determine how many uniform or varying locations a type
- * might occupy.
- */
- unsigned component_slots() const;
-
-
- /**
- * Query whether or not a type is a scalar (non-vector and non-matrix).
- */
- bool is_scalar() const
- {
- return (vector_elements == 1)
- && (base_type >= GLSL_TYPE_UINT)
- && (base_type <= GLSL_TYPE_BOOL);
- }
-
- /**
- * Query whether or not a type is a vector
- */
- bool is_vector() const
- {
- return (vector_elements > 1)
- && (matrix_columns == 1)
- && (base_type >= GLSL_TYPE_UINT)
- && (base_type <= GLSL_TYPE_BOOL);
- }
-
- /**
- * Query whether or not a type is a matrix
- */
- bool is_matrix() const
- {
- /* GLSL only has float matrices. */
- return (matrix_columns > 1) && (base_type == GLSL_TYPE_FLOAT);
- }
-
- /**
- * Query whether or not a type is a non-array numeric type
- */
- bool is_numeric() const
- {
- return (base_type >= GLSL_TYPE_UINT) && (base_type <= GLSL_TYPE_FLOAT);
- }
-
- /**
- * Query whether or not a type is an integral type
- */
- bool is_integer() const
- {
- return (base_type == GLSL_TYPE_UINT) || (base_type == GLSL_TYPE_INT);
- }
-
- /**
- * Query whether or not a type is a float type
- */
- bool is_float() const
- {
- return base_type == GLSL_TYPE_FLOAT;
- }
-
- /**
- * Query whether or not a type is a non-array boolean type
- */
- bool is_boolean() const
- {
- return base_type == GLSL_TYPE_BOOL;
- }
-
- /**
- * Query whether or not a type is a sampler
- */
- bool is_sampler() const
- {
- return base_type == GLSL_TYPE_SAMPLER;
- }
-
- /**
- * Query whether or not a type is an array
- */
- bool is_array() const
- {
- return base_type == GLSL_TYPE_ARRAY;
- }
-
- /**
- * Query whether or not a type is a record
- */
- bool is_record() const
- {
- return base_type == GLSL_TYPE_STRUCT;
- }
-
- /**
- * Query whether or not a type is the void type singleton.
- */
- bool is_void() const
- {
- return base_type == GLSL_TYPE_VOID;
- }
-
- /**
- * Query whether or not a type is the error type singleton.
- */
- bool is_error() const
- {
- return base_type == GLSL_TYPE_ERROR;
- }
-
- /**
- * Query the full type of a matrix row
- *
- * \return
- * If the type is not a matrix, \c glsl_type::error_type is returned.
- * Otherwise a type matching the rows of the matrix is returned.
- */
- const glsl_type *row_type() const
- {
- return is_matrix()
- ? get_instance(base_type, matrix_columns, 1)
- : error_type;
- }
-
- /**
- * Query the full type of a matrix column
- *
- * \return
- * If the type is not a matrix, \c glsl_type::error_type is returned.
- * Otherwise a type matching the columns of the matrix is returned.
- */
- const glsl_type *column_type() const
- {
- return is_matrix()
- ? get_instance(base_type, vector_elements, 1)
- : error_type;
- }
-
-
- /**
- * Get the type of a structure field
- *
- * \return
- * Pointer to the type of the named field. If the type is not a structure
- * or the named field does not exist, \c glsl_type::error_type is returned.
- */
- const glsl_type *field_type(const char *name) const;
-
-
- /**
- * Get the location of a filed within a record type
- */
- int field_index(const char *name) const;
-
-
- /**
- * Query the number of elements in an array type
- *
- * \return
- * The number of elements in the array for array types or -1 for non-array
- * types. If the number of elements in the array has not yet been declared,
- * zero is returned.
- */
- int array_size() const
- {
- return is_array() ? length : -1;
- }
-
-private:
- /**
- * ralloc context for all glsl_type allocations
- *
- * Set on the first call to \c glsl_type::new.
- */
- static void *mem_ctx;
-
- void init_ralloc_type_ctx(void);
-
- /** Constructor for vector and matrix types */
- glsl_type(GLenum gl_type,
- glsl_base_type base_type, unsigned vector_elements,
- unsigned matrix_columns, const char *name);
-
- /** Constructor for sampler types */
- glsl_type(GLenum gl_type,
- enum glsl_sampler_dim dim, bool shadow, bool array,
- unsigned type, const char *name);
-
- /** Constructor for record types */
- glsl_type(const glsl_struct_field *fields, unsigned num_fields,
- const char *name);
-
- /** Constructor for array types */
- glsl_type(const glsl_type *array, unsigned length);
-
- /** Hash table containing the known array types. */
- static struct hash_table *array_types;
-
- /** Hash table containing the known record types. */
- static struct hash_table *record_types;
-
- static int record_key_compare(const void *a, const void *b);
- static unsigned record_key_hash(const void *key);
-
- /**
- * \name Pointers to various type singletons
- */
- /*@{*/
- static const glsl_type _error_type;
- static const glsl_type _void_type;
- static const glsl_type _sampler3D_type;
- static const glsl_type builtin_core_types[];
- static const glsl_type builtin_structure_types[];
- static const glsl_type builtin_110_deprecated_structure_types[];
- static const glsl_type builtin_110_types[];
- static const glsl_type builtin_120_types[];
- static const glsl_type builtin_130_types[];
- static const glsl_type builtin_ARB_texture_rectangle_types[];
- static const glsl_type builtin_EXT_texture_array_types[];
- static const glsl_type builtin_EXT_texture_buffer_object_types[];
- /*@}*/
-
- /**
- * \name Methods to populate a symbol table with built-in types.
- *
- * \internal
- * This is one of the truely annoying things about C++. Methods that are
- * completely internal and private to a type still have to be advertised to
- * the world in a public header file.
- */
- /*@{*/
- static void generate_100ES_types(glsl_symbol_table *);
- static void generate_110_types(glsl_symbol_table *);
- static void generate_120_types(glsl_symbol_table *);
- static void generate_130_types(glsl_symbol_table *);
- static void generate_ARB_texture_rectangle_types(glsl_symbol_table *, bool);
- static void generate_EXT_texture_array_types(glsl_symbol_table *, bool);
- static void generate_OES_texture_3D_types(glsl_symbol_table *, bool);
- /*@}*/
-
- /**
- * \name Friend functions.
- *
- * These functions are friends because they must have C linkage and the
- * need to call various private methods or access various private static
- * data.
- */
- /*@{*/
- friend void _mesa_glsl_initialize_types(struct _mesa_glsl_parse_state *);
- friend void _mesa_glsl_release_types(void);
- /*@}*/
-};
-
-struct glsl_struct_field {
- const struct glsl_type *type;
- const char *name;
-};
-
-#endif /* GLSL_TYPES_H */
+/* -*- c++ -*- */ +/* + * 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 +#ifndef GLSL_TYPES_H +#define GLSL_TYPES_H + +#include <string.h> +#include <assert.h> + +extern "C" { +#include "GL/gl.h" +} + +#include "ralloc.h" + +struct _mesa_glsl_parse_state; +struct glsl_symbol_table; + +extern "C" void +_mesa_glsl_initialize_types(struct _mesa_glsl_parse_state *state); + +extern "C" void +_mesa_glsl_release_types(void); + +enum glsl_base_type { + GLSL_TYPE_UINT = 0, + GLSL_TYPE_INT, + GLSL_TYPE_FLOAT, + GLSL_TYPE_BOOL, + GLSL_TYPE_SAMPLER, + GLSL_TYPE_STRUCT, + GLSL_TYPE_ARRAY, + GLSL_TYPE_VOID, + GLSL_TYPE_ERROR +}; + +enum glsl_sampler_dim { + GLSL_SAMPLER_DIM_1D = 0, + GLSL_SAMPLER_DIM_2D, + GLSL_SAMPLER_DIM_3D, + GLSL_SAMPLER_DIM_CUBE, + GLSL_SAMPLER_DIM_RECT, + GLSL_SAMPLER_DIM_BUF +}; + + +struct glsl_type { + GLenum gl_type; + glsl_base_type base_type; + + unsigned sampler_dimensionality:3; /**< \see glsl_sampler_dim */ + unsigned sampler_shadow:1; + unsigned sampler_array:1; + unsigned sampler_type:2; /**< Type of data returned using this sampler. + * only \c GLSL_TYPE_FLOAT, \c GLSL_TYPE_INT, + * and \c GLSL_TYPE_UINT are valid. + */ + + /* Callers of this ralloc-based new need not call delete. It's + * easier to just ralloc_free 'mem_ctx' (or any of its ancestors). */ + static void* operator new(size_t size) + { + if (glsl_type::mem_ctx == NULL) { + glsl_type::mem_ctx = ralloc_context(NULL); + assert(glsl_type::mem_ctx != NULL); + } + + void *type; + + type = ralloc_size(glsl_type::mem_ctx, size); + assert(type != NULL); + + return type; + } + + /* If the user *does* call delete, that's OK, we will just + * ralloc_free in that case. */ + static void operator delete(void *type) + { + ralloc_free(type); + } + + /** + * \name Vector and matrix element counts + * + * For scalars, each of these values will be 1. For non-numeric types + * these will be 0. + */ + /*@{*/ + unsigned vector_elements:3; /**< 1, 2, 3, or 4 vector elements. */ + unsigned matrix_columns:3; /**< 1, 2, 3, or 4 matrix columns. */ + /*@}*/ + + /** + * Name of the data type + * + * This may be \c NULL for anonymous structures, for arrays, or for + * function types. + */ + const char *name; + + /** + * For \c GLSL_TYPE_ARRAY, this is the length of the array. For + * \c GLSL_TYPE_STRUCT, it is the number of elements in the structure and + * the number of values pointed to by \c fields.structure (below). + */ + unsigned length; + + /** + * Subtype of composite data types. + */ + union { + const struct glsl_type *array; /**< Type of array elements. */ + const struct glsl_type *parameters; /**< Parameters to function. */ + struct glsl_struct_field *structure; /**< List of struct fields. */ + } fields; + + + /** + * \name Pointers to various public type singletons + */ + /*@{*/ + static const glsl_type *const error_type; + static const glsl_type *const void_type; + static const glsl_type *const int_type; + static const glsl_type *const ivec4_type; + static const glsl_type *const uint_type; + static const glsl_type *const uvec2_type; + static const glsl_type *const uvec3_type; + static const glsl_type *const uvec4_type; + static const glsl_type *const float_type; + static const glsl_type *const vec2_type; + static const glsl_type *const vec3_type; + static const glsl_type *const vec4_type; + static const glsl_type *const bool_type; + static const glsl_type *const mat2_type; + static const glsl_type *const mat2x3_type; + static const glsl_type *const mat2x4_type; + static const glsl_type *const mat3x2_type; + static const glsl_type *const mat3_type; + static const glsl_type *const mat3x4_type; + static const glsl_type *const mat4x2_type; + static const glsl_type *const mat4x3_type; + static const glsl_type *const mat4_type; + /*@}*/ + + + /** + * For numeric and boolean derrived types returns the basic scalar type + * + * If the type is a numeric or boolean scalar, vector, or matrix type, + * this function gets the scalar type of the individual components. For + * all other types, including arrays of numeric or boolean types, the + * error type is returned. + */ + const glsl_type *get_base_type() const; + + /** + * Query the type of elements in an array + * + * \return + * Pointer to the type of elements in the array for array types, or \c NULL + * for non-array types. + */ + const glsl_type *element_type() const + { + return is_array() ? fields.array : NULL; + } + + /** + * Get the instance of a built-in scalar, vector, or matrix type + */ + static const glsl_type *get_instance(unsigned base_type, unsigned rows, + unsigned columns); + + /** + * Get the instance of an array type + */ + static const glsl_type *get_array_instance(const glsl_type *base, + unsigned elements); + + /** + * Get the instance of a record type + */ + static const glsl_type *get_record_instance(const glsl_struct_field *fields, + unsigned num_fields, + const char *name); + + /** + * Query the total number of scalars that make up a scalar, vector or matrix + */ + unsigned components() const + { + return vector_elements * matrix_columns; + } + + /** + * Calculate the number of components slots required to hold this type + * + * This is used to determine how many uniform or varying locations a type + * might occupy. + */ + unsigned component_slots() const; + + + /** + * Query whether or not a type is a scalar (non-vector and non-matrix). + */ + bool is_scalar() const + { + return (vector_elements == 1) + && (base_type >= GLSL_TYPE_UINT) + && (base_type <= GLSL_TYPE_BOOL); + } + + /** + * Query whether or not a type is a vector + */ + bool is_vector() const + { + return (vector_elements > 1) + && (matrix_columns == 1) + && (base_type >= GLSL_TYPE_UINT) + && (base_type <= GLSL_TYPE_BOOL); + } + + /** + * Query whether or not a type is a matrix + */ + bool is_matrix() const + { + /* GLSL only has float matrices. */ + return (matrix_columns > 1) && (base_type == GLSL_TYPE_FLOAT); + } + + /** + * Query whether or not a type is a non-array numeric type + */ + bool is_numeric() const + { + return (base_type >= GLSL_TYPE_UINT) && (base_type <= GLSL_TYPE_FLOAT); + } + + /** + * Query whether or not a type is an integral type + */ + bool is_integer() const + { + return (base_type == GLSL_TYPE_UINT) || (base_type == GLSL_TYPE_INT); + } + + /** + * Query whether or not a type is a float type + */ + bool is_float() const + { + return base_type == GLSL_TYPE_FLOAT; + } + + /** + * Query whether or not a type is a non-array boolean type + */ + bool is_boolean() const + { + return base_type == GLSL_TYPE_BOOL; + } + + /** + * Query whether or not a type is a sampler + */ + bool is_sampler() const + { + return base_type == GLSL_TYPE_SAMPLER; + } + + /** + * Query whether or not type is a sampler, or for struct and array + * types, contains a sampler. + */ + bool contains_sampler() const; + + /** + * Query whether or not a type is an array + */ + bool is_array() const + { + return base_type == GLSL_TYPE_ARRAY; + } + + /** + * Query whether or not a type is a record + */ + bool is_record() const + { + return base_type == GLSL_TYPE_STRUCT; + } + + /** + * Query whether or not a type is the void type singleton. + */ + bool is_void() const + { + return base_type == GLSL_TYPE_VOID; + } + + /** + * Query whether or not a type is the error type singleton. + */ + bool is_error() const + { + return base_type == GLSL_TYPE_ERROR; + } + + /** + * Query the full type of a matrix row + * + * \return + * If the type is not a matrix, \c glsl_type::error_type is returned. + * Otherwise a type matching the rows of the matrix is returned. + */ + const glsl_type *row_type() const + { + return is_matrix() + ? get_instance(base_type, matrix_columns, 1) + : error_type; + } + + /** + * Query the full type of a matrix column + * + * \return + * If the type is not a matrix, \c glsl_type::error_type is returned. + * Otherwise a type matching the columns of the matrix is returned. + */ + const glsl_type *column_type() const + { + return is_matrix() + ? get_instance(base_type, vector_elements, 1) + : error_type; + } + + + /** + * Get the type of a structure field + * + * \return + * Pointer to the type of the named field. If the type is not a structure + * or the named field does not exist, \c glsl_type::error_type is returned. + */ + const glsl_type *field_type(const char *name) const; + + + /** + * Get the location of a filed within a record type + */ + int field_index(const char *name) const; + + + /** + * Query the number of elements in an array type + * + * \return + * The number of elements in the array for array types or -1 for non-array + * types. If the number of elements in the array has not yet been declared, + * zero is returned. + */ + int array_size() const + { + return is_array() ? length : -1; + } + +private: + /** + * ralloc context for all glsl_type allocations + * + * Set on the first call to \c glsl_type::new. + */ + static void *mem_ctx; + + void init_ralloc_type_ctx(void); + + /** Constructor for vector and matrix types */ + glsl_type(GLenum gl_type, + glsl_base_type base_type, unsigned vector_elements, + unsigned matrix_columns, const char *name); + + /** Constructor for sampler types */ + glsl_type(GLenum gl_type, + enum glsl_sampler_dim dim, bool shadow, bool array, + unsigned type, const char *name); + + /** Constructor for record types */ + glsl_type(const glsl_struct_field *fields, unsigned num_fields, + const char *name); + + /** Constructor for array types */ + glsl_type(const glsl_type *array, unsigned length); + + /** Hash table containing the known array types. */ + static struct hash_table *array_types; + + /** Hash table containing the known record types. */ + static struct hash_table *record_types; + + static int record_key_compare(const void *a, const void *b); + static unsigned record_key_hash(const void *key); + + /** + * \name Pointers to various type singletons + */ + /*@{*/ + static const glsl_type _error_type; + static const glsl_type _void_type; + static const glsl_type _sampler3D_type; + static const glsl_type builtin_core_types[]; + static const glsl_type builtin_structure_types[]; + static const glsl_type builtin_110_deprecated_structure_types[]; + static const glsl_type builtin_110_types[]; + static const glsl_type builtin_120_types[]; + static const glsl_type builtin_130_types[]; + static const glsl_type builtin_ARB_texture_rectangle_types[]; + static const glsl_type builtin_EXT_texture_array_types[]; + static const glsl_type builtin_EXT_texture_buffer_object_types[]; + /*@}*/ + + /** + * \name Methods to populate a symbol table with built-in types. + * + * \internal + * This is one of the truely annoying things about C++. Methods that are + * completely internal and private to a type still have to be advertised to + * the world in a public header file. + */ + /*@{*/ + static void generate_100ES_types(glsl_symbol_table *); + static void generate_110_types(glsl_symbol_table *); + static void generate_120_types(glsl_symbol_table *); + static void generate_130_types(glsl_symbol_table *); + static void generate_ARB_texture_rectangle_types(glsl_symbol_table *, bool); + static void generate_EXT_texture_array_types(glsl_symbol_table *, bool); + static void generate_OES_texture_3D_types(glsl_symbol_table *, bool); + /*@}*/ + + /** + * \name Friend functions. + * + * These functions are friends because they must have C linkage and the + * need to call various private methods or access various private static + * data. + */ + /*@{*/ + friend void _mesa_glsl_initialize_types(struct _mesa_glsl_parse_state *); + friend void _mesa_glsl_release_types(void); + /*@}*/ +}; + +struct glsl_struct_field { + const struct glsl_type *type; + const char *name; +}; + +#endif /* GLSL_TYPES_H */ diff --git a/mesalib/src/glsl/ir.cpp b/mesalib/src/glsl/ir.cpp index 228e23732..4b35b8a90 100644 --- a/mesalib/src/glsl/ir.cpp +++ b/mesalib/src/glsl/ir.cpp @@ -1095,21 +1095,6 @@ ir_dereference_record::ir_dereference_record(ir_variable *var, ? this->record->type->field_type(field) : glsl_type::error_type;
}
-bool type_contains_sampler(const glsl_type *type)
-{
- if (type->is_array()) {
- return type_contains_sampler(type->fields.array);
- } else if (type->is_record()) {
- for (unsigned int i = 0; i < type->length; i++) {
- if (type_contains_sampler(type->fields.structure[i].type))
- return true;
- }
- return false;
- } else {
- return type->is_sampler();
- }
-}
-
bool
ir_dereference::is_lvalue()
{
@@ -1129,7 +1114,7 @@ ir_dereference::is_lvalue() * as out or inout function parameters, nor can they be
* assigned into."
*/
- if (type_contains_sampler(this->type))
+ if (this->type->contains_sampler())
return false;
return true;
diff --git a/mesalib/src/glsl/ir.h b/mesalib/src/glsl/ir.h index 926be9aef..8df2c42c3 100644 --- a/mesalib/src/glsl/ir.h +++ b/mesalib/src/glsl/ir.h @@ -1635,6 +1635,32 @@ visit_exec_list(exec_list *list, ir_visitor *visitor); */
void validate_ir_tree(exec_list *instructions);
+struct _mesa_glsl_parse_state;
+struct gl_shader_program;
+
+/**
+ * Detect whether an unlinked shader contains static recursion
+ *
+ * If the list of instructions is determined to contain static recursion,
+ * \c _mesa_glsl_error will be called to emit error messages for each function
+ * that is in the recursion cycle.
+ */
+void
+detect_recursion_unlinked(struct _mesa_glsl_parse_state *state,
+ exec_list *instructions);
+
+/**
+ * Detect whether a linked shader contains static recursion
+ *
+ * If the list of instructions is determined to contain static recursion,
+ * \c link_error_printf will be called to emit error messages for each function
+ * that is in the recursion cycle. In addition,
+ * \c gl_shader_program::LinkStatus will be set to false.
+ */
+void
+detect_recursion_linked(struct gl_shader_program *prog,
+ exec_list *instructions);
+
/**
* Make a clone of each IR instruction in a list
*
@@ -1669,4 +1695,8 @@ ir_has_call(ir_instruction *ir); extern void
do_set_program_inouts(exec_list *instructions, struct gl_program *prog);
+extern char *
+prototype_string(const glsl_type *return_type, const char *name,
+ exec_list *parameters);
+
#endif /* IR_H */
diff --git a/mesalib/src/glsl/ir_function_detect_recursion.cpp b/mesalib/src/glsl/ir_function_detect_recursion.cpp new file mode 100644 index 000000000..44a1cd0b9 --- /dev/null +++ b/mesalib/src/glsl/ir_function_detect_recursion.cpp @@ -0,0 +1,371 @@ +/* + * Copyright © 2011 Intel Corporation + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice (including the next + * paragraph) shall be included in all copies or substantial portions of the + * Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + */ + +/** + * \file ir_function_detect_recursion.cpp + * Determine whether a shader contains static recursion. + * + * Consider the (possibly disjoint) graph of function calls in a shader. If a + * program contains recursion, this graph will contain a cycle. If a function + * is part of a cycle, it will have a caller and it will have a callee (it + * calls another function). + * + * To detect recursion, the function call graph is constructed. The graph is + * repeatedly reduced by removing any function that either has no callees + * (leaf functions) or has no caller. Eventually the only functions that + * remain will be the functions in the cycles. + * + * The GLSL spec is a bit wishy-washy about recursion. + * + * From page 39 (page 45 of the PDF) of the GLSL 1.10 spec: + * + * "Behavior is undefined if recursion is used. Recursion means having any + * function appearing more than once at any one time in the run-time stack + * of function calls. That is, a function may not call itself either + * directly or indirectly. Compilers may give diagnostic messages when + * this is detectable at compile time, but not all such cases can be + * detected at compile time." + * + * From page 79 (page 85 of the PDF): + * + * "22) Should recursion be supported? + * + * DISCUSSION: Probably not necessary, but another example of limiting + * the language based on how it would directly map to hardware. One + * thought is that recursion would benefit ray tracing shaders. On the + * other hand, many recursion operations can also be implemented with the + * user managing the recursion through arrays. RenderMan doesn't support + * recursion. This could be added at a later date, if it proved to be + * necessary. + * + * RESOLVED on September 10, 2002: Implementations are not required to + * support recursion. + * + * CLOSED on September 10, 2002." + * + * From page 79 (page 85 of the PDF): + * + * "56) Is it an error for an implementation to support recursion if the + * specification says recursion is not supported? + * + * ADDED on September 10, 2002. + * + * DISCUSSION: This issues is related to Issue (22). If we say that + * recursion (or some other piece of functionality) is not supported, is + * it an error for an implementation to support it? Perhaps the + * specification should remain silent on these kind of things so that they + * could be gracefully added later as an extension or as part of the + * standard. + * + * RESOLUTION: Languages, in general, have programs that are not + * well-formed in ways a compiler cannot detect. Portability is only + * ensured for well-formed programs. Detecting recursion is an example of + * this. The language will say a well-formed program may not recurse, but + * compilers are not forced to detect that recursion may happen. + * + * CLOSED: November 29, 2002." + * + * In GLSL 1.10 the behavior of recursion is undefined. Compilers don't have + * to reject shaders (at compile-time or link-time) that contain recursion. + * Instead they could work, or crash, or kill a kitten. + * + * From page 44 (page 50 of the PDF) of the GLSL 1.20 spec: + * + * "Recursion is not allowed, not even statically. Static recursion is + * present if the static function call graph of the program contains + * cycles." + * + * This langauge clears things up a bit, but it still leaves a lot of + * questions unanswered. + * + * - Is the error generated at compile-time or link-time? + * + * - Is it an error to have a recursive function that is never statically + * called by main or any function called directly or indirectly by main? + * Technically speaking, such a function is not in the "static function + * call graph of the program" at all. + * + * \bug + * If a shader has multiple cycles, this algorithm may erroneously complain + * about functions that aren't in any cycle, but are in the part of the call + * tree that connects them. For example, if the call graph consists of a + * cycle between A and B, and a cycle between D and E, and B also calls C + * which calls D, then this algorithm will report C as a function which "has + * static recursion" even though it is not part of any cycle. + * + * A better algorithm for cycle detection that doesn't have this drawback can + * be found here: + * + * http://en.wikipedia.org/wiki/Tarjan%E2%80%99s_strongly_connected_components_algorithm + * + * \author Ian Romanick <ian.d.romanick@intel.com> + */ +#include "main/core.h" +#include "ir.h" +#include "glsl_parser_extras.h" +#include "linker.h" +#include "program/hash_table.h" + +struct call_node : public exec_node { + class function *func; +}; + +class function { +public: + function(ir_function_signature *sig) + : sig(sig) + { + /* empty */ + } + + + /* Callers of this ralloc-based new need not call delete. It's + * easier to just ralloc_free 'ctx' (or any of its ancestors). */ + static void* operator new(size_t size, void *ctx) + { + void *node; + + node = ralloc_size(ctx, size); + assert(node != NULL); + + return node; + } + + /* If the user *does* call delete, that's OK, we will just + * ralloc_free in that case. */ + static void operator delete(void *node) + { + ralloc_free(node); + } + + ir_function_signature *sig; + + /** List of functions called by this function. */ + exec_list callees; + + /** List of functions that call this function. */ + exec_list callers; +}; + +class has_recursion_visitor : public ir_hierarchical_visitor { +public: + has_recursion_visitor() + : current(NULL) + { + this->mem_ctx = ralloc_context(NULL); + this->function_hash = hash_table_ctor(0, hash_table_pointer_hash, + hash_table_pointer_compare); + } + + ~has_recursion_visitor() + { + hash_table_dtor(this->function_hash); + ralloc_free(this->mem_ctx); + } + + function *get_function(ir_function_signature *sig) + { + function *f = (function *) hash_table_find(this->function_hash, sig); + if (f == NULL) { + f = new(mem_ctx) function(sig); + hash_table_insert(this->function_hash, f, sig); + } + + return f; + } + + virtual ir_visitor_status visit_enter(ir_function_signature *sig) + { + this->current = this->get_function(sig); + return visit_continue; + } + + virtual ir_visitor_status visit_leave(ir_function_signature *sig) + { + (void) sig; + this->current = NULL; + return visit_continue; + } + + virtual ir_visitor_status visit_enter(ir_call *call) + { + /* At global scope this->current will be NULL. Since there is no way to + * call global scope, it can never be part of a cycle. Don't bother + * adding calls from global scope to the graph. + */ + if (this->current == NULL) + return visit_continue; + + function *const target = this->get_function(call->get_callee()); + + /* Create a link from the caller to the callee. + */ + call_node *node = new(mem_ctx) call_node; + node->func = target; + this->current->callees.push_tail(node); + + /* Create a link from the callee to the caller. + */ + node = new(mem_ctx) call_node; + node->func = this->current; + target->callers.push_tail(node); + return visit_continue; + } + + function *current; + struct hash_table *function_hash; + void *mem_ctx; + bool progress; +}; + +static void +destroy_links(exec_list *list, function *f) +{ + foreach_list_safe(node, list) { + struct call_node *n = (struct call_node *) node; + + /* If this is the right function, remove it. Note that the loop cannot + * terminate now. There can be multiple links to a function if it is + * either called multiple times or calls multiple times. + */ + if (n->func == f) + n->remove(); + } +} + + +/** + * Remove a function if it has either no in or no out links + */ +static void +remove_unlinked_functions(const void *key, void *data, void *closure) +{ + has_recursion_visitor *visitor = (has_recursion_visitor *) closure; + function *f = (function *) data; + + if (f->callers.is_empty() || f->callees.is_empty()) { + while (!f->callers.is_empty()) { + struct call_node *n = (struct call_node *) f->callers.pop_head(); + destroy_links(& n->func->callees, f); + } + + while (!f->callees.is_empty()) { + struct call_node *n = (struct call_node *) f->callees.pop_head(); + destroy_links(& n->func->callers, f); + } + + hash_table_remove(visitor->function_hash, key); + visitor->progress = true; + } +} + + +static void +emit_errors_unlinked(const void *key, void *data, void *closure) +{ + struct _mesa_glsl_parse_state *state = + (struct _mesa_glsl_parse_state *) closure; + function *f = (function *) data; + YYLTYPE loc; + + char *proto = prototype_string(f->sig->return_type, + f->sig->function_name(), + &f->sig->parameters); + + memset(&loc, 0, sizeof(loc)); + _mesa_glsl_error(&loc, state, + "function `%s' has static recursion.", + proto); + ralloc_free(proto); +} + + +static void +emit_errors_linked(const void *key, void *data, void *closure) +{ + struct gl_shader_program *prog = + (struct gl_shader_program *) closure; + function *f = (function *) data; + + char *proto = prototype_string(f->sig->return_type, + f->sig->function_name(), + &f->sig->parameters); + + linker_error_printf(prog, + "function `%s' has static recursion.\n", + proto); + ralloc_free(proto); + prog->LinkStatus = false; +} + + +void +detect_recursion_unlinked(struct _mesa_glsl_parse_state *state, + exec_list *instructions) +{ + has_recursion_visitor v; + + /* Collect all of the information about which functions call which other + * functions. + */ + v.run(instructions); + + /* Remove from the set all of the functions that either have no caller or + * call no other functions. Repeat until no functions are removed. + */ + do { + v.progress = false; + hash_table_call_foreach(v.function_hash, remove_unlinked_functions, & v); + } while (v.progress); + + + /* At this point any functions still in the hash must be part of a cycle. + */ + hash_table_call_foreach(v.function_hash, emit_errors_unlinked, state); +} + + +void +detect_recursion_linked(struct gl_shader_program *prog, + exec_list *instructions) +{ + has_recursion_visitor v; + + /* Collect all of the information about which functions call which other + * functions. + */ + v.run(instructions); + + /* Remove from the set all of the functions that either have no caller or + * call no other functions. Repeat until no functions are removed. + */ + do { + v.progress = false; + hash_table_call_foreach(v.function_hash, remove_unlinked_functions, & v); + } while (v.progress); + + + /* At this point any functions still in the hash must be part of a cycle. + */ + hash_table_call_foreach(v.function_hash, emit_errors_linked, prog); +} diff --git a/mesalib/src/glsl/linker.cpp b/mesalib/src/glsl/linker.cpp index e0d7efa23..cfadfd5e3 100644 --- a/mesalib/src/glsl/linker.cpp +++ b/mesalib/src/glsl/linker.cpp @@ -1343,7 +1343,7 @@ assign_attribute_or_color_locations(gl_shader_program *prog, foreach_list(node, sh->ir) {
ir_variable *const var = ((ir_instruction *) node)->as_variable();
- if ((var == NULL) || (var->mode != direction))
+ if ((var == NULL) || (var->mode != (unsigned) direction))
continue;
if (var->explicit_location) {
@@ -1702,6 +1702,10 @@ link_shaders(struct gl_context *ctx, struct gl_shader_program *prog) if (prog->_LinkedShaders[i] == NULL)
continue;
+ detect_recursion_linked(prog, prog->_LinkedShaders[i]->ir);
+ if (!prog->LinkStatus)
+ goto done;
+
while (do_common_optimization(prog->_LinkedShaders[i]->ir, true, 32))
;
}
diff --git a/mesalib/src/glsl/s_expression.cpp b/mesalib/src/glsl/s_expression.cpp index b47b014c6..b6a51c34e 100644 --- a/mesalib/src/glsl/s_expression.cpp +++ b/mesalib/src/glsl/s_expression.cpp @@ -25,10 +25,13 @@ #include <assert.h>
#include "s_expression.h"
-s_symbol::s_symbol(const char *tmp, size_t n)
+s_symbol::s_symbol(const char *str, size_t n)
{
- this->str = ralloc_strndup (this, tmp, n);
- assert(this->str != NULL);
+ /* Assume the given string is already nul-terminated and in memory that
+ * will live as long as this node.
+ */
+ assert(str[n] == '\0');
+ this->str = str;
}
s_list::s_list()
@@ -36,22 +39,26 @@ s_list::s_list() }
static void
-skip_whitespace(const char *& src)
+skip_whitespace(const char *&src, char *&symbol_buffer)
{
- src += strspn(src, " \v\t\r\n");
+ size_t n = strspn(src, " \v\t\r\n");
+ src += n;
+ symbol_buffer += n;
/* Also skip Scheme-style comments: semi-colon 'til end of line */
if (src[0] == ';') {
- src += strcspn(src, "\n");
- skip_whitespace(src);
+ n = strcspn(src, "\n");
+ src += n;
+ symbol_buffer += n;
+ skip_whitespace(src, symbol_buffer);
}
}
static s_expression *
-read_atom(void *ctx, const char *& src)
+read_atom(void *ctx, const char *&src, char *&symbol_buffer)
{
s_expression *expr = NULL;
- skip_whitespace(src);
+ skip_whitespace(src, symbol_buffer);
size_t n = strcspn(src, "( \v\t\r\n);");
if (n == 0)
@@ -70,44 +77,65 @@ read_atom(void *ctx, const char *& src) expr = new(ctx) s_int(i);
} else {
// Not a number; return a symbol.
- expr = new(ctx) s_symbol(src, n);
+ symbol_buffer[n] = '\0';
+ expr = new(ctx) s_symbol(symbol_buffer, n);
}
src += n;
+ symbol_buffer += n;
return expr;
}
-s_expression *
-s_expression::read_expression(void *ctx, const char *&src)
+static s_expression *
+__read_expression(void *ctx, const char *&src, char *&symbol_buffer)
{
- assert(src != NULL);
-
- s_expression *atom = read_atom(ctx, src);
+ s_expression *atom = read_atom(ctx, src, symbol_buffer);
if (atom != NULL)
return atom;
- skip_whitespace(src);
+ skip_whitespace(src, symbol_buffer);
if (src[0] == '(') {
++src;
+ ++symbol_buffer;
s_list *list = new(ctx) s_list;
s_expression *expr;
- while ((expr = read_expression(ctx, src)) != NULL) {
+ while ((expr = __read_expression(ctx, src, symbol_buffer)) != NULL) {
list->subexpressions.push_tail(expr);
}
- skip_whitespace(src);
+ skip_whitespace(src, symbol_buffer);
if (src[0] != ')') {
printf("Unclosed expression (check your parenthesis).\n");
return NULL;
}
++src;
+ ++symbol_buffer;
return list;
}
return NULL;
}
+s_expression *
+s_expression::read_expression(void *ctx, const char *&src)
+{
+ assert(src != NULL);
+
+ /* When we encounter a Symbol, we need to save a nul-terminated copy of
+ * the string. However, ralloc_strndup'ing every individual Symbol is
+ * extremely expensive. We could avoid this by simply overwriting the
+ * next character (guaranteed to be whitespace, parens, or semicolon) with
+ * a nul-byte. But overwriting non-whitespace would mess up parsing.
+ *
+ * So, just copy the whole buffer ahead of time. Walk both, leaving the
+ * original source string unmodified, and altering the copy to contain the
+ * necessary nul-bytes whenever we encounter a symbol.
+ */
+ char *symbol_buffer = ralloc_strdup(ctx, src);
+ return __read_expression(ctx, src, symbol_buffer);
+}
+
void s_int::print()
{
printf("%d", this->val);
diff --git a/mesalib/src/glsl/s_expression.h b/mesalib/src/glsl/s_expression.h index c9dc676b3..642af19b4 100644 --- a/mesalib/src/glsl/s_expression.h +++ b/mesalib/src/glsl/s_expression.h @@ -129,7 +129,7 @@ public: void print(); private: - char *str; + const char *str; }; /* Lists of expressions: (expr1 ... exprN) */ diff --git a/mesalib/src/mesa/drivers/common/driverfuncs.c b/mesalib/src/mesa/drivers/common/driverfuncs.c index 4806d5d67..a2687d7c3 100644 --- a/mesalib/src/mesa/drivers/common/driverfuncs.c +++ b/mesalib/src/mesa/drivers/common/driverfuncs.c @@ -95,8 +95,6 @@ _mesa_init_driver_functions(struct dd_function_table *driver) driver->TexSubImage2D = _mesa_store_texsubimage2d;
driver->TexSubImage3D = _mesa_store_texsubimage3d;
driver->GetTexImage = _mesa_get_teximage;
- driver->CopyTexImage1D = _mesa_meta_CopyTexImage1D;
- driver->CopyTexImage2D = _mesa_meta_CopyTexImage2D;
driver->CopyTexSubImage1D = _mesa_meta_CopyTexSubImage1D;
driver->CopyTexSubImage2D = _mesa_meta_CopyTexSubImage2D;
driver->CopyTexSubImage3D = _mesa_meta_CopyTexSubImage3D;
diff --git a/mesalib/src/mesa/drivers/common/meta.c b/mesalib/src/mesa/drivers/common/meta.c index 0e58aeca3..fa78674e4 100644 --- a/mesalib/src/mesa/drivers/common/meta.c +++ b/mesalib/src/mesa/drivers/common/meta.c @@ -62,6 +62,7 @@ #include "main/teximage.h" #include "main/texparam.h" #include "main/texstate.h" +#include "main/uniforms.h" #include "main/varray.h" #include "main/viewport.h" #include "program/program.h" @@ -235,6 +236,8 @@ struct clear_state { GLuint ArrayObj; GLuint VBO; + GLuint ShaderProg; + GLint ColorLocation; }; @@ -1589,10 +1592,165 @@ _mesa_meta_Clear(struct gl_context *ctx, GLbitfield buffers) _mesa_meta_end(ctx); } +static void +meta_glsl_clear_init(struct gl_context *ctx, struct clear_state *clear) +{ + const char *vs_source = + "attribute vec4 position;\n" + "void main()\n" + "{\n" + " gl_Position = position;\n" + "}\n"; + const char *fs_source = + "uniform vec4 color;\n" + "void main()\n" + "{\n" + " gl_FragColor = color;\n" + "}\n"; + GLuint vs, fs; + + if (clear->ArrayObj != 0) + return; + + /* create vertex array object */ + _mesa_GenVertexArrays(1, &clear->ArrayObj); + _mesa_BindVertexArray(clear->ArrayObj); + + /* create vertex array buffer */ + _mesa_GenBuffersARB(1, &clear->VBO); + _mesa_BindBufferARB(GL_ARRAY_BUFFER_ARB, clear->VBO); + + /* setup vertex arrays */ + _mesa_VertexAttribPointerARB(0, 3, GL_FLOAT, GL_FALSE, 0, (void *)0); + _mesa_EnableVertexAttribArrayARB(0); + + vs = _mesa_CreateShaderObjectARB(GL_VERTEX_SHADER); + _mesa_ShaderSourceARB(vs, 1, &vs_source, NULL); + _mesa_CompileShaderARB(vs); + + fs = _mesa_CreateShaderObjectARB(GL_FRAGMENT_SHADER); + _mesa_ShaderSourceARB(fs, 1, &fs_source, NULL); + _mesa_CompileShaderARB(fs); + + clear->ShaderProg = _mesa_CreateProgramObjectARB(); + _mesa_AttachShader(clear->ShaderProg, fs); + _mesa_AttachShader(clear->ShaderProg, vs); + _mesa_BindAttribLocationARB(clear->ShaderProg, 0, "position"); + _mesa_LinkProgramARB(clear->ShaderProg); + + clear->ColorLocation = _mesa_GetUniformLocationARB(clear->ShaderProg, + "color"); +} + +/** + * Meta implementation of ctx->Driver.Clear() in terms of polygon rendering. + */ +void +_mesa_meta_glsl_Clear(struct gl_context *ctx, GLbitfield buffers) +{ + struct clear_state *clear = &ctx->Meta->Clear; + GLbitfield metaSave; + const GLuint stencilMax = (1 << ctx->DrawBuffer->Visual.stencilBits) - 1; + struct gl_framebuffer *fb = ctx->DrawBuffer; + const float x0 = ((float)fb->_Xmin / fb->Width) * 2.0f - 1.0f; + const float y0 = ((float)fb->_Ymin / fb->Height) * 2.0f - 1.0f; + const float x1 = ((float)fb->_Xmax / fb->Width) * 2.0f - 1.0f; + const float y1 = ((float)fb->_Ymax / fb->Height) * 2.0f - 1.0f; + const float z = -invert_z(ctx->Depth.Clear); + struct vertex { + GLfloat x, y, z; + } verts[4]; + + metaSave = (META_ALPHA_TEST | + META_BLEND | + META_DEPTH_TEST | + META_RASTERIZATION | + META_SHADER | + META_STENCIL_TEST | + META_VERTEX | + META_VIEWPORT | + META_CLAMP_FRAGMENT_COLOR); + + if (!(buffers & BUFFER_BITS_COLOR)) { + /* We'll use colormask to disable color writes. Otherwise, + * respect color mask + */ + metaSave |= META_COLOR_MASK; + } + + _mesa_meta_begin(ctx, metaSave); + + meta_glsl_clear_init(ctx, clear); + + _mesa_UseProgramObjectARB(clear->ShaderProg); + _mesa_Uniform4fvARB(clear->ColorLocation, 1, + ctx->Color.ClearColorUnclamped); + + _mesa_BindVertexArray(clear->ArrayObj); + _mesa_BindBufferARB(GL_ARRAY_BUFFER_ARB, clear->VBO); + + /* GL_COLOR_BUFFER_BIT */ + if (buffers & BUFFER_BITS_COLOR) { + /* leave colormask, glDrawBuffer state as-is */ + + /* Clears never have the color clamped. */ + _mesa_ClampColorARB(GL_CLAMP_FRAGMENT_COLOR, GL_FALSE); + } + else { + ASSERT(metaSave & META_COLOR_MASK); + _mesa_ColorMask(GL_FALSE, GL_FALSE, GL_FALSE, GL_FALSE); + } + + /* GL_DEPTH_BUFFER_BIT */ + if (buffers & BUFFER_BIT_DEPTH) { + _mesa_set_enable(ctx, GL_DEPTH_TEST, GL_TRUE); + _mesa_DepthFunc(GL_ALWAYS); + _mesa_DepthMask(GL_TRUE); + } + else { + assert(!ctx->Depth.Test); + } + + /* GL_STENCIL_BUFFER_BIT */ + if (buffers & BUFFER_BIT_STENCIL) { + _mesa_set_enable(ctx, GL_STENCIL_TEST, GL_TRUE); + _mesa_StencilOpSeparate(GL_FRONT_AND_BACK, + GL_REPLACE, GL_REPLACE, GL_REPLACE); + _mesa_StencilFuncSeparate(GL_FRONT_AND_BACK, GL_ALWAYS, + ctx->Stencil.Clear & stencilMax, + ctx->Stencil.WriteMask[0]); + } + else { + assert(!ctx->Stencil.Enabled); + } + + /* vertex positions */ + verts[0].x = x0; + verts[0].y = y0; + verts[0].z = z; + verts[1].x = x1; + verts[1].y = y0; + verts[1].z = z; + verts[2].x = x1; + verts[2].y = y1; + verts[2].z = z; + verts[3].x = x0; + verts[3].y = y1; + verts[3].z = z; + + /* upload new vertex data */ + _mesa_BufferDataARB(GL_ARRAY_BUFFER_ARB, sizeof(verts), verts, + GL_DYNAMIC_DRAW_ARB); + + /* draw quad */ + _mesa_DrawArrays(GL_TRIANGLE_FAN, 0, 4); + + _mesa_meta_end(ctx); +} /** * Meta implementation of ctx->Driver.CopyPixels() in terms - * of texture mapping and polygon rendering. + * of texture mapping and polygon rendering and GLSL shaders. */ void _mesa_meta_CopyPixels(struct gl_context *ctx, GLint srcX, GLint srcY, @@ -2678,119 +2836,6 @@ get_temp_image_type(struct gl_context *ctx, GLenum baseFormat) /** - * Helper for _mesa_meta_CopyTexImage1/2D() functions. - * Have to be careful with locking and meta state for pixel transfer. - */ -static void -copy_tex_image(struct gl_context *ctx, GLuint dims, GLenum target, GLint level, - GLenum internalFormat, GLint x, GLint y, - GLsizei width, GLsizei height, GLint border) -{ - struct gl_texture_object *texObj; - struct gl_texture_image *texImage; - GLenum format, type; - GLint bpp; - void *buf; - struct gl_renderbuffer *read_rb = ctx->ReadBuffer->_ColorReadBuffer; - - texObj = _mesa_get_current_tex_object(ctx, target); - texImage = _mesa_get_tex_image(ctx, texObj, target, level); - - /* Choose format/type for temporary image buffer */ - format = _mesa_base_tex_format(ctx, internalFormat); - - if (format == GL_LUMINANCE && - _mesa_get_format_base_format(read_rb->Format) != GL_LUMINANCE) { - /* The glReadPixels() path will convert RGB to luminance by - * summing R+G+B. glCopyTexImage() is supposed to behave as - * glCopyPixels, which doesn't do that change, and instead - * leaves it up to glTexImage which converts RGB to luminance by - * just taking the R channel. To avoid glReadPixels() trashing - * our data, use RGBA for our temporary image. - */ - format = GL_RGBA; - } - - type = get_temp_image_type(ctx, format); - bpp = _mesa_bytes_per_pixel(format, type); - if (bpp <= 0) { - _mesa_problem(ctx, "Bad bpp in meta copy_tex_image()"); - return; - } - - /* - * Alloc image buffer (XXX could use a PBO) - */ - buf = malloc(width * height * bpp); - if (!buf) { - _mesa_error(ctx, GL_OUT_OF_MEMORY, "glCopyTexImage%uD", dims); - return; - } - - _mesa_unlock_texture(ctx, texObj); /* need to unlock first */ - - /* - * Read image from framebuffer (disable pixel transfer ops) - */ - _mesa_meta_begin(ctx, META_PIXEL_STORE | META_PIXEL_TRANSFER); - ctx->Driver.ReadPixels(ctx, x, y, width, height, - format, type, &ctx->Pack, buf); - _mesa_meta_end(ctx); - - if (texImage->Data) { - ctx->Driver.FreeTexImageData(ctx, texImage); - } - - /* The texture's format was already chosen in _mesa_CopyTexImage() */ - ASSERT(texImage->TexFormat != MESA_FORMAT_NONE); - - /* - * Store texture data (with pixel transfer ops) - */ - _mesa_meta_begin(ctx, META_PIXEL_STORE); - - _mesa_update_state(ctx); /* to update pixel transfer state */ - - if (target == GL_TEXTURE_1D) { - ctx->Driver.TexImage1D(ctx, target, level, internalFormat, - width, border, format, type, - buf, &ctx->Unpack, texObj, texImage); - } - else { - ctx->Driver.TexImage2D(ctx, target, level, internalFormat, - width, height, border, format, type, - buf, &ctx->Unpack, texObj, texImage); - } - _mesa_meta_end(ctx); - - _mesa_lock_texture(ctx, texObj); /* re-lock */ - - free(buf); -} - - -void -_mesa_meta_CopyTexImage1D(struct gl_context *ctx, GLenum target, GLint level, - GLenum internalFormat, GLint x, GLint y, - GLsizei width, GLint border) -{ - copy_tex_image(ctx, 1, target, level, internalFormat, x, y, - width, 1, border); -} - - -void -_mesa_meta_CopyTexImage2D(struct gl_context *ctx, GLenum target, GLint level, - GLenum internalFormat, GLint x, GLint y, - GLsizei width, GLsizei height, GLint border) -{ - copy_tex_image(ctx, 2, target, level, internalFormat, x, y, - width, height, border); -} - - - -/** * Helper for _mesa_meta_CopyTexSubImage1/2/3D() functions. * Have to be careful with locking and meta state for pixel transfer. */ diff --git a/mesalib/src/mesa/drivers/common/meta.h b/mesalib/src/mesa/drivers/common/meta.h index a350a92aa..95b4b5579 100644 --- a/mesalib/src/mesa/drivers/common/meta.h +++ b/mesalib/src/mesa/drivers/common/meta.h @@ -1,118 +1,111 @@ -/*
- * Mesa 3-D graphics library
- * Version: 7.6
- *
- * 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 META_H
-#define META_H
-
-
-extern void
-_mesa_meta_init(struct gl_context *ctx);
-
-extern void
-_mesa_meta_free(struct gl_context *ctx);
-
-extern void
-_mesa_meta_BlitFramebuffer(struct gl_context *ctx,
- GLint srcX0, GLint srcY0, GLint srcX1, GLint srcY1,
- GLint dstX0, GLint dstY0, GLint dstX1, GLint dstY1,
- GLbitfield mask, GLenum filter);
-
-extern void
-_mesa_meta_Clear(struct gl_context *ctx, GLbitfield buffers);
-
-extern void
-_mesa_meta_CopyPixels(struct gl_context *ctx, GLint srcx, GLint srcy,
- GLsizei width, GLsizei height,
- GLint dstx, GLint dsty, GLenum type);
-
-extern void
-_mesa_meta_DrawPixels(struct gl_context *ctx,
- GLint x, GLint y, GLsizei width, GLsizei height,
- GLenum format, GLenum type,
- const struct gl_pixelstore_attrib *unpack,
- const GLvoid *pixels);
-
-extern void
-_mesa_meta_Bitmap(struct gl_context *ctx,
- GLint x, GLint y, GLsizei width, GLsizei height,
- const struct gl_pixelstore_attrib *unpack,
- const GLubyte *bitmap);
-
-extern GLboolean
-_mesa_meta_check_generate_mipmap_fallback(struct gl_context *ctx, GLenum target,
- struct gl_texture_object *texObj);
-
-extern void
-_mesa_meta_GenerateMipmap(struct gl_context *ctx, GLenum target,
- struct gl_texture_object *texObj);
-
-extern void
-_mesa_meta_CopyTexImage1D(struct gl_context *ctx, GLenum target, GLint level,
- GLenum internalFormat, GLint x, GLint y,
- GLsizei width, GLint border);
-
-extern void
-_mesa_meta_CopyTexImage2D(struct gl_context *ctx, GLenum target, GLint level,
- GLenum internalFormat, GLint x, GLint y,
- GLsizei width, GLsizei height, GLint border);
-
-extern void
-_mesa_meta_CopyTexSubImage1D(struct gl_context *ctx, GLenum target, GLint level,
- GLint xoffset,
- GLint x, GLint y, GLsizei width);
-
-extern void
-_mesa_meta_CopyTexSubImage2D(struct gl_context *ctx, GLenum target, GLint level,
- GLint xoffset, GLint yoffset,
- GLint x, GLint y,
- GLsizei width, GLsizei height);
-
-extern void
-_mesa_meta_CopyTexSubImage3D(struct gl_context *ctx, GLenum target, GLint level,
- GLint xoffset, GLint yoffset, GLint zoffset,
- GLint x, GLint y,
- GLsizei width, GLsizei height);
-
-extern void
-_mesa_meta_CopyColorTable(struct gl_context *ctx,
- GLenum target, GLenum internalformat,
- GLint x, GLint y, GLsizei width);
-
-extern void
-_mesa_meta_CopyColorSubTable(struct gl_context *ctx,GLenum target, GLsizei start,
- GLint x, GLint y, GLsizei width);
-
-extern void
-_mesa_meta_CopyConvolutionFilter1D(struct gl_context *ctx, GLenum target,
- GLenum internalFormat,
- GLint x, GLint y, GLsizei width);
-
-extern void
-_mesa_meta_CopyConvolutionFilter2D(struct gl_context *ctx, GLenum target,
- GLenum internalFormat, GLint x, GLint y,
- GLsizei width, GLsizei height);
-
-
-#endif /* META_H */
+/* + * Mesa 3-D graphics library + * Version: 7.6 + * + * 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 META_H +#define META_H + + +extern void +_mesa_meta_init(struct gl_context *ctx); + +extern void +_mesa_meta_free(struct gl_context *ctx); + +extern void +_mesa_meta_BlitFramebuffer(struct gl_context *ctx, + GLint srcX0, GLint srcY0, GLint srcX1, GLint srcY1, + GLint dstX0, GLint dstY0, GLint dstX1, GLint dstY1, + GLbitfield mask, GLenum filter); + +extern void +_mesa_meta_Clear(struct gl_context *ctx, GLbitfield buffers); + +extern void +_mesa_meta_glsl_Clear(struct gl_context *ctx, GLbitfield buffers); + +extern void +_mesa_meta_CopyPixels(struct gl_context *ctx, GLint srcx, GLint srcy, + GLsizei width, GLsizei height, + GLint dstx, GLint dsty, GLenum type); + +extern void +_mesa_meta_DrawPixels(struct gl_context *ctx, + GLint x, GLint y, GLsizei width, GLsizei height, + GLenum format, GLenum type, + const struct gl_pixelstore_attrib *unpack, + const GLvoid *pixels); + +extern void +_mesa_meta_Bitmap(struct gl_context *ctx, + GLint x, GLint y, GLsizei width, GLsizei height, + const struct gl_pixelstore_attrib *unpack, + const GLubyte *bitmap); + +extern GLboolean +_mesa_meta_check_generate_mipmap_fallback(struct gl_context *ctx, GLenum target, + struct gl_texture_object *texObj); + +extern void +_mesa_meta_GenerateMipmap(struct gl_context *ctx, GLenum target, + struct gl_texture_object *texObj); + +extern void +_mesa_meta_CopyTexSubImage1D(struct gl_context *ctx, GLenum target, GLint level, + GLint xoffset, + GLint x, GLint y, GLsizei width); + +extern void +_mesa_meta_CopyTexSubImage2D(struct gl_context *ctx, GLenum target, GLint level, + GLint xoffset, GLint yoffset, + GLint x, GLint y, + GLsizei width, GLsizei height); + +extern void +_mesa_meta_CopyTexSubImage3D(struct gl_context *ctx, GLenum target, GLint level, + GLint xoffset, GLint yoffset, GLint zoffset, + GLint x, GLint y, + GLsizei width, GLsizei height); + +extern void +_mesa_meta_CopyColorTable(struct gl_context *ctx, + GLenum target, GLenum internalformat, + GLint x, GLint y, GLsizei width); + +extern void +_mesa_meta_CopyColorSubTable(struct gl_context *ctx,GLenum target, GLsizei start, + GLint x, GLint y, GLsizei width); + +extern void +_mesa_meta_CopyConvolutionFilter1D(struct gl_context *ctx, GLenum target, + GLenum internalFormat, + GLint x, GLint y, GLsizei width); + +extern void +_mesa_meta_CopyConvolutionFilter2D(struct gl_context *ctx, GLenum target, + GLenum internalFormat, GLint x, GLint y, + GLsizei width, GLsizei height); + + +#endif /* META_H */ diff --git a/mesalib/src/mesa/main/dd.h b/mesalib/src/mesa/main/dd.h index d16b14b6a..aae68439a 100644 --- a/mesalib/src/mesa/main/dd.h +++ b/mesalib/src/mesa/main/dd.h @@ -189,31 +189,22 @@ struct dd_function_table { /*@{*/
/**
- * Choose texture format.
- *
- * This is called by the \c _mesa_store_tex[sub]image[123]d() fallback
- * functions. The driver should examine \p internalFormat and return a
- * gl_format value.
+ * Choose actual hardware texture format given the user-provided source
+ * image format and type and the desired internal format. In some
+ * cases, srcFormat and srcType can be GL_NONE.
+ * Called by glTexImage(), etc.
*/
GLuint (*ChooseTextureFormat)( struct gl_context *ctx, GLint internalFormat,
GLenum srcFormat, GLenum srcType );
/**
- * Called by glTexImage1D().
- *
- * \param target user specified.
- * \param format user specified.
- * \param type user specified.
- * \param pixels user specified.
- * \param packing indicates the image packing of pixels.
+ * Called by glTexImage1D(). Simply copy the source texture data into the
+ * destination texture memory. The gl_texture_image fields, etc. will be
+ * fully initialized.
+ * The parameters are the same as glTexImage1D(), plus:
+ * \param packing describes how to unpack the source data.
* \param texObj is the target texture object.
- * \param texImage is the target texture image. It will have the texture \p
- * width, \p height, \p depth, \p border and \p internalFormat information.
- *
- * \p retainInternalCopy is returned by this function and indicates whether
- * core Mesa should keep an internal copy of the texture image.
- *
- * Drivers should call a fallback routine from texstore.c if needed.
+ * \param texImage is the target texture image.
*/
void (*TexImage1D)( struct gl_context *ctx, GLenum target, GLint level,
GLint internalFormat,
@@ -250,25 +241,9 @@ struct dd_function_table { struct gl_texture_image *texImage );
/**
- * Called by glTexSubImage1D().
- *
- * \param target user specified.
- * \param level user specified.
- * \param xoffset user specified.
- * \param yoffset user specified.
- * \param zoffset user specified.
- * \param width user specified.
- * \param height user specified.
- * \param depth user specified.
- * \param format user specified.
- * \param type user specified.
- * \param pixels user specified.
- * \param packing indicates the image packing of pixels.
- * \param texObj is the target texture object.
- * \param texImage is the target texture image. It will have the texture \p
- * width, \p height, \p border and \p internalFormat information.
- *
- * The driver should use a fallback routine from texstore.c if needed.
+ * Called by glTexSubImage1D(). Replace a subset of the target texture
+ * with new texel data.
+ * \sa dd_function_table::TexImage1D.
*/
void (*TexSubImage1D)( struct gl_context *ctx, GLenum target, GLint level,
GLint xoffset, GLsizei width,
@@ -315,24 +290,6 @@ struct dd_function_table { struct gl_texture_image *texImage );
/**
- * Called by glCopyTexImage1D().
- *
- * Drivers should use a fallback routine from texstore.c if needed.
- */
- void (*CopyTexImage1D)( struct gl_context *ctx, GLenum target, GLint level,
- GLenum internalFormat, GLint x, GLint y,
- GLsizei width, GLint border );
-
- /**
- * Called by glCopyTexImage2D().
- *
- * Drivers should use a fallback routine from texstore.c if needed.
- */
- void (*CopyTexImage2D)( struct gl_context *ctx, GLenum target, GLint level,
- GLenum internalFormat, GLint x, GLint y,
- GLsizei width, GLsizei height, GLint border );
-
- /**
* Called by glCopyTexSubImage1D().
*
* Drivers should use a fallback routine from texstore.c if needed.
diff --git a/mesalib/src/mesa/main/fbobject.c b/mesalib/src/mesa/main/fbobject.c index 7bb5f03f1..7c31d2577 100644 --- a/mesalib/src/mesa/main/fbobject.c +++ b/mesalib/src/mesa/main/fbobject.c @@ -2134,10 +2134,14 @@ _mesa_GetFramebufferAttachmentParameterivEXT(GLenum target, GLenum attachment, {
const struct gl_renderbuffer_attachment *att;
struct gl_framebuffer *buffer;
+ GLenum err;
GET_CURRENT_CONTEXT(ctx);
ASSERT_OUTSIDE_BEGIN_END(ctx);
+ /* The error differs in GL andd GLES. */
+ err = ctx->API == API_OPENGL ? GL_INVALID_OPERATION : GL_INVALID_ENUM;
+
buffer = get_framebuffer_target(ctx, target);
if (!buffer) {
_mesa_error(ctx, GL_INVALID_ENUM,
@@ -2188,7 +2192,12 @@ _mesa_GetFramebufferAttachmentParameterivEXT(GLenum target, GLenum attachment, }
else {
assert(att->Type == GL_NONE);
- *params = 0;
+ if (ctx->API == API_OPENGL) {
+ *params = 0;
+ } else {
+ _mesa_error(ctx, GL_INVALID_ENUM,
+ "glGetFramebufferAttachmentParameterivEXT(pname)");
+ }
}
return;
case GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_LEVEL_EXT:
@@ -2196,7 +2205,7 @@ _mesa_GetFramebufferAttachmentParameterivEXT(GLenum target, GLenum attachment, *params = att->TextureLevel;
}
else if (att->Type == GL_NONE) {
- _mesa_error(ctx, GL_INVALID_OPERATION,
+ _mesa_error(ctx, err,
"glGetFramebufferAttachmentParameterivEXT(pname)");
}
else {
@@ -2214,7 +2223,7 @@ _mesa_GetFramebufferAttachmentParameterivEXT(GLenum target, GLenum attachment, }
}
else if (att->Type == GL_NONE) {
- _mesa_error(ctx, GL_INVALID_OPERATION,
+ _mesa_error(ctx, err,
"glGetFramebufferAttachmentParameterivEXT(pname)");
}
else {
@@ -2232,7 +2241,7 @@ _mesa_GetFramebufferAttachmentParameterivEXT(GLenum target, GLenum attachment, }
}
else if (att->Type == GL_NONE) {
- _mesa_error(ctx, GL_INVALID_OPERATION,
+ _mesa_error(ctx, err,
"glGetFramebufferAttachmentParameterivEXT(pname)");
}
else {
@@ -2246,7 +2255,7 @@ _mesa_GetFramebufferAttachmentParameterivEXT(GLenum target, GLenum attachment, "glGetFramebufferAttachmentParameterivEXT(pname)");
}
else if (att->Type == GL_NONE) {
- _mesa_error(ctx, GL_INVALID_OPERATION,
+ _mesa_error(ctx, err,
"glGetFramebufferAttachmentParameterivEXT(pname)");
}
else {
@@ -2267,7 +2276,7 @@ _mesa_GetFramebufferAttachmentParameterivEXT(GLenum target, GLenum attachment, return;
}
else if (att->Type == GL_NONE) {
- _mesa_error(ctx, GL_INVALID_OPERATION,
+ _mesa_error(ctx, err,
"glGetFramebufferAttachmentParameterivEXT(pname)");
}
else {
@@ -2301,7 +2310,7 @@ _mesa_GetFramebufferAttachmentParameterivEXT(GLenum target, GLenum attachment, "glGetFramebufferAttachmentParameterivEXT(pname)");
}
else if (att->Type == GL_NONE) {
- _mesa_error(ctx, GL_INVALID_OPERATION,
+ _mesa_error(ctx, err,
"glGetFramebufferAttachmentParameterivEXT(pname)");
}
else if (att->Texture) {
diff --git a/mesalib/src/mesa/main/teximage.c b/mesalib/src/mesa/main/teximage.c index 7493cd65b..7141efba1 100644 --- a/mesalib/src/mesa/main/teximage.c +++ b/mesalib/src/mesa/main/teximage.c @@ -2797,29 +2797,43 @@ copyteximage(struct gl_context *ctx, GLuint dims, _mesa_error(ctx, GL_OUT_OF_MEMORY, "glCopyTexImage%uD", dims);
}
else {
- gl_format texFormat;
-
- if (texImage->Data) {
- ctx->Driver.FreeTexImageData( ctx, texImage );
- }
+ /* choose actual hw format */
+ gl_format texFormat = _mesa_choose_texture_format(ctx, texObj,
+ target, level,
+ internalFormat,
+ GL_NONE, GL_NONE);
- ASSERT(texImage->Data == NULL);
+ if (legal_texture_size(ctx, texFormat, width, height, 1)) {
+ GLint srcX = x, srcY = y, dstX = 0, dstY = 0;
- texFormat = _mesa_choose_texture_format(ctx, texObj, target, level,
- internalFormat, GL_NONE,
- GL_NONE);
+ /* Free old texture image */
+ ctx->Driver.FreeTexImageData(ctx, texImage);
- if (legal_texture_size(ctx, texFormat, width, height, 1)) {
_mesa_init_teximage_fields(ctx, target, texImage, width, height, 1,
border, internalFormat, texFormat);
- ASSERT(ctx->Driver.CopyTexImage2D);
- if (dims == 1)
- ctx->Driver.CopyTexImage1D(ctx, target, level, internalFormat,
- x, y, width, border);
- else
- ctx->Driver.CopyTexImage2D(ctx, target, level, internalFormat,
- x, y, width, height, border);
+ /* Allocate texture memory (no pixel data yet) */
+ if (dims == 1) {
+ ctx->Driver.TexImage1D(ctx, target, level, internalFormat,
+ width, border, GL_NONE, GL_NONE, NULL,
+ &ctx->Unpack, texObj, texImage);
+ }
+ else {
+ ctx->Driver.TexImage2D(ctx, target, level, internalFormat,
+ width, height, border, GL_NONE, GL_NONE,
+ NULL, &ctx->Unpack, texObj, texImage);
+ }
+
+ if (_mesa_clip_copytexsubimage(ctx, &dstX, &dstY, &srcX, &srcY,
+ &width, &height)) {
+ if (dims == 1)
+ ctx->Driver.CopyTexSubImage1D(ctx, target, level, dstX,
+ srcX, srcY, width);
+
+ else
+ ctx->Driver.CopyTexSubImage2D(ctx, target, level, dstX, dstY,
+ srcX, srcY, width, height);
+ }
check_gen_mipmap(ctx, target, texObj, level);
@@ -2830,6 +2844,7 @@ copyteximage(struct gl_context *ctx, GLuint dims, ctx->NewState |= _NEW_TEXTURE;
}
else {
+ /* probably too large of image */
_mesa_error(ctx, GL_OUT_OF_MEMORY, "glCopyTexImage%uD", dims);
}
}
diff --git a/mesalib/src/mesa/main/texstore.c b/mesalib/src/mesa/main/texstore.c index 6e1e63bdf..c4aeaa8f1 100644 --- a/mesalib/src/mesa/main/texstore.c +++ b/mesalib/src/mesa/main/texstore.c @@ -4577,8 +4577,7 @@ texture_row_stride(const struct gl_texture_image *texImage) /** - * This is the software fallback for Driver.TexImage1D() - * and Driver.CopyTexImage1D(). + * This is the software fallback for Driver.TexImage1D(). * \sa _mesa_store_teximage2d() */ void @@ -4629,8 +4628,7 @@ _mesa_store_teximage1d(struct gl_context *ctx, GLenum target, GLint level, /** - * This is the software fallback for Driver.TexImage2D() - * and Driver.CopyTexImage2D(). + * This is the software fallback for Driver.TexImage2D(). * * This function is oriented toward storing images in main memory, rather * than VRAM. Device driver's can easily plug in their own replacement. @@ -4684,8 +4682,7 @@ _mesa_store_teximage2d(struct gl_context *ctx, GLenum target, GLint level, /** - * This is the software fallback for Driver.TexImage3D() - * and Driver.CopyTexImage3D(). + * This is the software fallback for Driver.TexImage3D(). * \sa _mesa_store_teximage2d() */ void diff --git a/mesalib/src/mesa/state_tracker/st_cb_texture.c b/mesalib/src/mesa/state_tracker/st_cb_texture.c index 1b75f699d..7f6ffee5e 100644 --- a/mesalib/src/mesa/state_tracker/st_cb_texture.c +++ b/mesalib/src/mesa/state_tracker/st_cb_texture.c @@ -1466,34 +1466,6 @@ st_copy_texsubimage(struct gl_context *ctx, depth/stencil samples per pixel? Need some transfer clarifications. */
assert(sample_count < 2);
- if (srcX < 0) {
- width -= -srcX;
- destX += -srcX;
- srcX = 0;
- }
-
- if (srcY < 0) {
- height -= -srcY;
- destY += -srcY;
- srcY = 0;
- }
-
- if (destX < 0) {
- width -= -destX;
- srcX += -destX;
- destX = 0;
- }
-
- if (destY < 0) {
- height -= -destY;
- srcY += -destY;
- destY = 0;
- }
-
- if (width < 0 || height < 0)
- return;
-
-
assert(strb);
assert(strb->surface);
assert(stImage->pt);
@@ -1610,59 +1582,6 @@ st_copy_texsubimage(struct gl_context *ctx, static void
-st_CopyTexImage1D(struct gl_context * ctx, GLenum target, GLint level,
- GLenum internalFormat,
- GLint x, GLint y, GLsizei width, GLint border)
-{
- struct gl_texture_unit *texUnit =
- &ctx->Texture.Unit[ctx->Texture.CurrentUnit];
- struct gl_texture_object *texObj =
- _mesa_select_tex_object(ctx, texUnit, target);
- struct gl_texture_image *texImage =
- _mesa_select_tex_image(ctx, texObj, target, level);
-
- /* Setup or redefine the texture object, texture and texture
- * image. Don't populate yet.
- */
- ctx->Driver.TexImage1D(ctx, target, level, internalFormat,
- width, border,
- GL_RGBA, CHAN_TYPE, NULL,
- &ctx->DefaultPacking, texObj, texImage);
-
- st_copy_texsubimage(ctx, target, level,
- 0, 0, 0, /* destX,Y,Z */
- x, y, width, 1); /* src X, Y, size */
-}
-
-
-static void
-st_CopyTexImage2D(struct gl_context * ctx, GLenum target, GLint level,
- GLenum internalFormat,
- GLint x, GLint y, GLsizei width, GLsizei height,
- GLint border)
-{
- struct gl_texture_unit *texUnit =
- &ctx->Texture.Unit[ctx->Texture.CurrentUnit];
- struct gl_texture_object *texObj =
- _mesa_select_tex_object(ctx, texUnit, target);
- struct gl_texture_image *texImage =
- _mesa_select_tex_image(ctx, texObj, target, level);
-
- /* Setup or redefine the texture object, texture and texture
- * image. Don't populate yet.
- */
- ctx->Driver.TexImage2D(ctx, target, level, internalFormat,
- width, height, border,
- GL_RGBA, CHAN_TYPE, NULL,
- &ctx->DefaultPacking, texObj, texImage);
-
- st_copy_texsubimage(ctx, target, level,
- 0, 0, 0, /* destX,Y,Z */
- x, y, width, height); /* src X, Y, size */
-}
-
-
-static void
st_CopyTexSubImage1D(struct gl_context * ctx, GLenum target, GLint level,
GLint xoffset, GLint x, GLint y, GLsizei width)
{
@@ -1947,8 +1866,6 @@ st_init_texture_functions(struct dd_function_table *functions) functions->CompressedTexSubImage1D = st_CompressedTexSubImage1D;
functions->CompressedTexSubImage2D = st_CompressedTexSubImage2D;
functions->CompressedTexSubImage3D = st_CompressedTexSubImage3D;
- functions->CopyTexImage1D = st_CopyTexImage1D;
- functions->CopyTexImage2D = st_CopyTexImage2D;
functions->CopyTexSubImage1D = st_CopyTexSubImage1D;
functions->CopyTexSubImage2D = st_CopyTexSubImage2D;
functions->CopyTexSubImage3D = st_CopyTexSubImage3D;
diff --git a/mesalib/src/mesa/state_tracker/st_manager.c b/mesalib/src/mesa/state_tracker/st_manager.c index 7bd82aae2..d5228d387 100644 --- a/mesalib/src/mesa/state_tracker/st_manager.c +++ b/mesalib/src/mesa/state_tracker/st_manager.c @@ -587,7 +587,7 @@ st_context_teximage(struct st_context_iface *stctxi, internalFormat = GL_RGB; texFormat = st_ChooseTextureFormat(ctx, internalFormat, - GL_RGBA, GL_UNSIGNED_BYTE); + GL_BGRA, GL_UNSIGNED_BYTE); _mesa_init_teximage_fields(ctx, target, texImage, tex->width0, tex->height0, 1, 0, |