| /* |
| * Mesa 3-D graphics library |
| * Version: 6.5 |
| * |
| * Copyright (C) 2005-2006 Brian Paul All Rights Reserved. |
| * |
| * Permission is hereby granted, free of charge, to any person obtaining a |
| * copy of this software and associated documentation files (the "Software"), |
| * to deal in the Software without restriction, including without limitation |
| * the rights to use, copy, modify, merge, publish, distribute, sublicense, |
| * and/or sell copies of the Software, and to permit persons to whom the |
| * Software is furnished to do so, subject to the following conditions: |
| * |
| * The above copyright notice and this permission notice shall be included |
| * in all copies or substantial portions of the Software. |
| * |
| * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS |
| * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, |
| * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL |
| * BRIAN PAUL BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN |
| * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN |
| * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. |
| */ |
| |
| /** |
| * \file slang_assemble_constructor.c |
| * slang constructor and vector swizzle assembler |
| * \author Michal Krol |
| */ |
| |
| #include "imports.h" |
| #include "slang_assemble.h" |
| #include "slang_storage.h" |
| |
| /* _slang_is_swizzle() */ |
| |
| GLboolean _slang_is_swizzle (const char *field, GLuint rows, slang_swizzle *swz) |
| { |
| GLuint i; |
| GLboolean xyzw = GL_FALSE, rgba = GL_FALSE, stpq = GL_FALSE; |
| |
| /* the swizzle can be at most 4-component long */ |
| swz->num_components = slang_string_length (field); |
| if (swz->num_components > 4) |
| return GL_FALSE; |
| |
| for (i = 0; i < swz->num_components; i++) |
| { |
| /* mark which swizzle group is used */ |
| switch (field[i]) |
| { |
| case 'x': |
| case 'y': |
| case 'z': |
| case 'w': |
| xyzw = GL_TRUE; |
| break; |
| case 'r': |
| case 'g': |
| case 'b': |
| case 'a': |
| rgba = GL_TRUE; |
| break; |
| case 's': |
| case 't': |
| case 'p': |
| case 'q': |
| stpq = GL_TRUE; |
| break; |
| default: |
| return GL_FALSE; |
| } |
| |
| /* collect swizzle component */ |
| switch (field[i]) |
| { |
| case 'x': |
| case 'r': |
| case 's': |
| swz->swizzle[i] = 0; |
| break; |
| case 'y': |
| case 'g': |
| case 't': |
| swz->swizzle[i] = 1; |
| break; |
| case 'z': |
| case 'b': |
| case 'p': |
| swz->swizzle[i] = 2; |
| break; |
| case 'w': |
| case 'a': |
| case 'q': |
| swz->swizzle[i] = 3; |
| break; |
| } |
| |
| /* check if the component is valid for given vector's row count */ |
| if (rows <= swz->swizzle[i]) |
| return GL_FALSE; |
| } |
| |
| /* only one swizzle group can be used */ |
| if ((xyzw && rgba) || (xyzw && stpq) || (rgba && stpq)) |
| return GL_FALSE; |
| |
| return GL_TRUE; |
| } |
| |
| /* _slang_is_swizzle_mask() */ |
| |
| GLboolean _slang_is_swizzle_mask (const slang_swizzle *swz, GLuint rows) |
| { |
| GLuint i, c = 0; |
| |
| /* the swizzle may not be longer than the vector dim */ |
| if (swz->num_components > rows) |
| return GL_FALSE; |
| |
| /* the swizzle components cannot be duplicated */ |
| for (i = 0; i < swz->num_components; i++) |
| { |
| if ((c & (1 << swz->swizzle[i])) != 0) |
| return GL_FALSE; |
| c |= 1 << swz->swizzle[i]; |
| } |
| |
| return GL_TRUE; |
| } |
| |
| /* _slang_multiply_swizzles() */ |
| |
| GLvoid _slang_multiply_swizzles (slang_swizzle *dst, const slang_swizzle *left, |
| const slang_swizzle *right) |
| { |
| GLuint i; |
| |
| dst->num_components = right->num_components; |
| for (i = 0; i < right->num_components; i++) |
| dst->swizzle[i] = left->swizzle[right->swizzle[i]]; |
| } |
| |
| /* _slang_assemble_constructor() */ |
| |
| static GLboolean |
| sizeof_argument (slang_assemble_ctx *A, GLuint *size, slang_operation *op) |
| { |
| slang_assembly_typeinfo ti; |
| GLboolean result = GL_FALSE; |
| slang_storage_aggregate agg; |
| |
| if (!slang_assembly_typeinfo_construct (&ti)) |
| return GL_FALSE; |
| if (!_slang_typeof_operation (A, op, &ti)) |
| goto end1; |
| |
| if (!slang_storage_aggregate_construct (&agg)) |
| goto end1; |
| if (!_slang_aggregate_variable (&agg, &ti.spec, 0, A->space.funcs, A->space.structs, |
| A->space.vars, A->mach, A->file, A->atoms)) |
| goto end; |
| |
| *size = _slang_sizeof_aggregate (&agg); |
| result = GL_TRUE; |
| |
| end: |
| slang_storage_aggregate_destruct (&agg); |
| end1: |
| slang_assembly_typeinfo_destruct (&ti); |
| return result; |
| } |
| |
| static GLboolean constructor_aggregate (slang_assemble_ctx *A, const slang_storage_aggregate *flat, |
| slang_operation *op, GLuint garbage_size) |
| { |
| slang_assembly_typeinfo ti; |
| GLboolean result = GL_FALSE; |
| slang_storage_aggregate agg, flat_agg; |
| |
| if (!slang_assembly_typeinfo_construct (&ti)) |
| return GL_FALSE; |
| if (!_slang_typeof_operation (A, op, &ti)) |
| goto end1; |
| |
| if (!slang_storage_aggregate_construct (&agg)) |
| goto end1; |
| if (!_slang_aggregate_variable (&agg, &ti.spec, 0, A->space.funcs, A->space.structs, |
| A->space.vars, A->mach, A->file, A->atoms)) |
| goto end2; |
| |
| if (!slang_storage_aggregate_construct (&flat_agg)) |
| goto end2; |
| if (!_slang_flatten_aggregate (&flat_agg, &agg)) |
| goto end; |
| |
| if (!_slang_assemble_operation (A, op, slang_ref_forbid)) |
| goto end; |
| |
| /* TODO: convert (generic) elements */ |
| |
| /* free the garbage */ |
| if (garbage_size != 0) |
| { |
| GLuint i; |
| |
| /* move the non-garbage part to the end of the argument */ |
| if (!slang_assembly_file_push_label (A->file, slang_asm_addr_push, 0)) |
| goto end; |
| for (i = flat_agg.count * 4 - garbage_size; i > 0; i -= 4) |
| { |
| if (!slang_assembly_file_push_label2 (A->file, slang_asm_float_move, |
| garbage_size + i, i)) |
| { |
| goto end; |
| } |
| } |
| if (!slang_assembly_file_push_label (A->file, slang_asm_local_free, garbage_size + 4)) |
| goto end; |
| } |
| |
| result = GL_TRUE; |
| end: |
| slang_storage_aggregate_destruct (&flat_agg); |
| end2: |
| slang_storage_aggregate_destruct (&agg); |
| end1: |
| slang_assembly_typeinfo_destruct (&ti); |
| return result; |
| } |
| |
| GLboolean _slang_assemble_constructor (slang_assemble_ctx *A, slang_operation *op) |
| { |
| slang_assembly_typeinfo ti; |
| GLboolean result = GL_FALSE; |
| slang_storage_aggregate agg, flat; |
| GLuint size, i; |
| GLuint arg_sums[2]; |
| |
| /* get typeinfo of the constructor (the result of constructor expression) */ |
| if (!slang_assembly_typeinfo_construct (&ti)) |
| return GL_FALSE; |
| if (!_slang_typeof_operation (A, op, &ti)) |
| goto end1; |
| |
| /* create an aggregate of the constructor */ |
| if (!slang_storage_aggregate_construct (&agg)) |
| goto end1; |
| if (!_slang_aggregate_variable (&agg, &ti.spec, 0, A->space.funcs, A->space.structs, |
| A->space.vars, A->mach, A->file, A->atoms)) |
| goto end2; |
| |
| /* calculate size of the constructor */ |
| size = _slang_sizeof_aggregate (&agg); |
| |
| /* flatten the constructor */ |
| if (!slang_storage_aggregate_construct (&flat)) |
| goto end2; |
| if (!_slang_flatten_aggregate (&flat, &agg)) |
| goto end; |
| |
| /* collect the last two constructor's argument size sums */ |
| arg_sums[0] = 0; /* will hold all but the last argument's size sum */ |
| arg_sums[1] = 0; /* will hold all argument's size sum */ |
| for (i = 0; i < op->num_children; i++) |
| { |
| GLuint arg_size = 0; |
| |
| if (!sizeof_argument (A, &arg_size, &op->children[i])) |
| goto end; |
| if (i > 0) |
| arg_sums[0] = arg_sums[1]; |
| arg_sums[1] += arg_size; |
| } |
| |
| /* check if there are too many arguments */ |
| if (arg_sums[0] >= size) |
| { |
| /* TODO: info log: too many arguments in constructor list */ |
| goto end; |
| } |
| |
| /* check if there are too few arguments */ |
| if (arg_sums[1] < size) |
| { |
| /* TODO: info log: too few arguments in constructor list */ |
| goto end; |
| } |
| |
| /* traverse the children that form the constructor expression */ |
| for (i = op->num_children; i > 0; i--) |
| { |
| GLuint garbage_size; |
| |
| /* the last argument may be too big - calculate the unnecessary data size */ |
| if (i == op->num_children) |
| garbage_size = arg_sums[1] - size; |
| else |
| garbage_size = 0; |
| |
| if (!constructor_aggregate (A, &flat, &op->children[i - 1], garbage_size)) |
| goto end; |
| } |
| |
| result = GL_TRUE; |
| end: |
| slang_storage_aggregate_destruct (&flat); |
| end2: |
| slang_storage_aggregate_destruct (&agg); |
| end1: |
| slang_assembly_typeinfo_destruct (&ti); |
| return result; |
| } |
| |
| /* _slang_assemble_constructor_from_swizzle() */ |
| |
| GLboolean _slang_assemble_constructor_from_swizzle (slang_assemble_ctx *A, const slang_swizzle *swz, |
| slang_type_specifier *spec, slang_type_specifier *master_spec) |
| { |
| GLuint master_rows, i; |
| |
| master_rows = _slang_type_dim (master_spec->type); |
| for (i = 0; i < master_rows; i++) |
| { |
| switch (_slang_type_base (master_spec->type)) |
| { |
| case slang_spec_bool: |
| if (!slang_assembly_file_push_label2 (A->file, slang_asm_bool_copy, |
| (master_rows - i) * 4, i * 4)) |
| return GL_FALSE; |
| break; |
| case slang_spec_int: |
| if (!slang_assembly_file_push_label2 (A->file, slang_asm_int_copy, |
| (master_rows - i) * 4, i * 4)) |
| return GL_FALSE; |
| break; |
| case slang_spec_float: |
| if (!slang_assembly_file_push_label2 (A->file, slang_asm_float_copy, |
| (master_rows - i) * 4, i * 4)) |
| return GL_FALSE; |
| break; |
| default: |
| break; |
| } |
| } |
| if (!slang_assembly_file_push_label (A->file, slang_asm_local_free, 4)) |
| return GL_FALSE; |
| for (i = swz->num_components; i > 0; i--) |
| { |
| GLuint n = i - 1; |
| |
| if (!slang_assembly_file_push_label2 (A->file, slang_asm_local_addr, A->local.swizzle_tmp, 16)) |
| return GL_FALSE; |
| if (!slang_assembly_file_push_label (A->file, slang_asm_addr_push, swz->swizzle[n] * 4)) |
| return GL_FALSE; |
| if (!slang_assembly_file_push (A->file, slang_asm_addr_add)) |
| return GL_FALSE; |
| switch (_slang_type_base (master_spec->type)) |
| { |
| case slang_spec_bool: |
| if (!slang_assembly_file_push (A->file, slang_asm_bool_deref)) |
| return GL_FALSE; |
| break; |
| case slang_spec_int: |
| if (!slang_assembly_file_push (A->file, slang_asm_int_deref)) |
| return GL_FALSE; |
| break; |
| case slang_spec_float: |
| if (!slang_assembly_file_push (A->file, slang_asm_float_deref)) |
| return GL_FALSE; |
| break; |
| default: |
| break; |
| } |
| } |
| |
| return GL_TRUE; |
| } |
| |