diff options
Diffstat (limited to 'lib/mesa/src')
56 files changed, 2381 insertions, 320 deletions
diff --git a/lib/mesa/src/compiler/blob.c b/lib/mesa/src/compiler/blob.c new file mode 100644 index 000000000..8dd254fef --- /dev/null +++ b/lib/mesa/src/compiler/blob.c @@ -0,0 +1,384 @@ +/* + * Copyright © 2014 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. + */ + +#include <string.h> + +#include "main/macros.h" +#include "blob.h" + +#ifdef HAVE_VALGRIND +#include <valgrind.h> +#include <memcheck.h> +#define VG(x) x +#else +#define VG(x) +#endif + +#define BLOB_INITIAL_SIZE 4096 + +/* Ensure that \blob will be able to fit an additional object of size + * \additional. The growing (if any) will occur by doubling the existing + * allocation. + */ +static bool +grow_to_fit(struct blob *blob, size_t additional) +{ + size_t to_allocate; + uint8_t *new_data; + + if (blob->out_of_memory) + return false; + + if (blob->size + additional <= blob->allocated) + return true; + + if (blob->fixed_allocation) { + blob->out_of_memory = true; + return false; + } + + if (blob->allocated == 0) + to_allocate = BLOB_INITIAL_SIZE; + else + to_allocate = blob->allocated * 2; + + to_allocate = MAX2(to_allocate, blob->allocated + additional); + + new_data = realloc(blob->data, to_allocate); + if (new_data == NULL) { + blob->out_of_memory = true; + return false; + } + + blob->data = new_data; + blob->allocated = to_allocate; + + return true; +} + +/* Align the blob->size so that reading or writing a value at (blob->data + + * blob->size) will result in an access aligned to a granularity of \alignment + * bytes. + * + * \return True unless allocation fails + */ +static bool +align_blob(struct blob *blob, size_t alignment) +{ + const size_t new_size = ALIGN(blob->size, alignment); + + if (blob->size < new_size) { + if (!grow_to_fit(blob, new_size - blob->size)) + return false; + + if (blob->data) + memset(blob->data + blob->size, 0, new_size - blob->size); + blob->size = new_size; + } + + return true; +} + +static void +align_blob_reader(struct blob_reader *blob, size_t alignment) +{ + blob->current = blob->data + ALIGN(blob->current - blob->data, alignment); +} + +void +blob_init(struct blob *blob) +{ + blob->data = NULL; + blob->allocated = 0; + blob->size = 0; + blob->fixed_allocation = false; + blob->out_of_memory = false; +} + +void +blob_init_fixed(struct blob *blob, void *data, size_t size) +{ + blob->data = data; + blob->allocated = size; + blob->size = 0; + blob->fixed_allocation = true; + blob->out_of_memory = false; +} + +bool +blob_overwrite_bytes(struct blob *blob, + size_t offset, + const void *bytes, + size_t to_write) +{ + /* Detect an attempt to overwrite data out of bounds. */ + if (offset + to_write < offset || blob->size < offset + to_write) + return false; + + VG(VALGRIND_CHECK_MEM_IS_DEFINED(bytes, to_write)); + + if (blob->data) + memcpy(blob->data + offset, bytes, to_write); + + return true; +} + +bool +blob_write_bytes(struct blob *blob, const void *bytes, size_t to_write) +{ + if (! grow_to_fit(blob, to_write)) + return false; + + VG(VALGRIND_CHECK_MEM_IS_DEFINED(bytes, to_write)); + + if (blob->data) + memcpy(blob->data + blob->size, bytes, to_write); + blob->size += to_write; + + return true; +} + +intptr_t +blob_reserve_bytes(struct blob *blob, size_t to_write) +{ + intptr_t ret; + + if (! grow_to_fit (blob, to_write)) + return -1; + + ret = blob->size; + blob->size += to_write; + + return ret; +} + +intptr_t +blob_reserve_uint32(struct blob *blob) +{ + align_blob(blob, sizeof(uint32_t)); + return blob_reserve_bytes(blob, sizeof(uint32_t)); +} + +intptr_t +blob_reserve_intptr(struct blob *blob) +{ + align_blob(blob, sizeof(intptr_t)); + return blob_reserve_bytes(blob, sizeof(intptr_t)); +} + +bool +blob_write_uint32(struct blob *blob, uint32_t value) +{ + align_blob(blob, sizeof(value)); + + return blob_write_bytes(blob, &value, sizeof(value)); +} + +#define ASSERT_ALIGNED(_offset, _align) \ + assert(ALIGN((_offset), (_align)) == (_offset)) + +bool +blob_overwrite_uint32 (struct blob *blob, + size_t offset, + uint32_t value) +{ + ASSERT_ALIGNED(offset, sizeof(value)); + return blob_overwrite_bytes(blob, offset, &value, sizeof(value)); +} + +bool +blob_write_uint64(struct blob *blob, uint64_t value) +{ + align_blob(blob, sizeof(value)); + + return blob_write_bytes(blob, &value, sizeof(value)); +} + +bool +blob_write_intptr(struct blob *blob, intptr_t value) +{ + align_blob(blob, sizeof(value)); + + return blob_write_bytes(blob, &value, sizeof(value)); +} + +bool +blob_overwrite_intptr (struct blob *blob, + size_t offset, + intptr_t value) +{ + ASSERT_ALIGNED(offset, sizeof(value)); + return blob_overwrite_bytes(blob, offset, &value, sizeof(value)); +} + +bool +blob_write_string(struct blob *blob, const char *str) +{ + return blob_write_bytes(blob, str, strlen(str) + 1); +} + +void +blob_reader_init(struct blob_reader *blob, const void *data, size_t size) +{ + blob->data = data; + blob->end = blob->data + size; + blob->current = data; + blob->overrun = false; +} + +/* Check that an object of size \size can be read from this blob. + * + * If not, set blob->overrun to indicate that we attempted to read too far. + */ +static bool +ensure_can_read(struct blob_reader *blob, size_t size) +{ + if (blob->overrun) + return false; + + if (blob->current < blob->end && blob->end - blob->current >= size) + return true; + + blob->overrun = true; + + return false; +} + +const void * +blob_read_bytes(struct blob_reader *blob, size_t size) +{ + const void *ret; + + if (! ensure_can_read (blob, size)) + return NULL; + + ret = blob->current; + + blob->current += size; + + return ret; +} + +void +blob_copy_bytes(struct blob_reader *blob, void *dest, size_t size) +{ + const void *bytes; + + bytes = blob_read_bytes(blob, size); + if (bytes == NULL) + return; + + memcpy(dest, bytes, size); +} + +/* These next three read functions have identical form. If we add any beyond + * these first three we should probably switch to generating these with a + * preprocessor macro. +*/ +uint32_t +blob_read_uint32(struct blob_reader *blob) +{ + uint32_t ret; + int size = sizeof(ret); + + align_blob_reader(blob, size); + + if (! ensure_can_read(blob, size)) + return 0; + + ret = *((uint32_t*) blob->current); + + blob->current += size; + + return ret; +} + +uint64_t +blob_read_uint64(struct blob_reader *blob) +{ + uint64_t ret; + int size = sizeof(ret); + + align_blob_reader(blob, size); + + if (! ensure_can_read(blob, size)) + return 0; + + ret = *((uint64_t*) blob->current); + + blob->current += size; + + return ret; +} + +intptr_t +blob_read_intptr(struct blob_reader *blob) +{ + intptr_t ret; + int size = sizeof(ret); + + align_blob_reader(blob, size); + + if (! ensure_can_read(blob, size)) + return 0; + + ret = *((intptr_t *) blob->current); + + blob->current += size; + + return ret; +} + +char * +blob_read_string(struct blob_reader *blob) +{ + int size; + char *ret; + uint8_t *nul; + + /* If we're already at the end, then this is an overrun. */ + if (blob->current >= blob->end) { + blob->overrun = true; + return NULL; + } + + /* Similarly, if there is no zero byte in the data remaining in this blob, + * we also consider that an overrun. + */ + nul = memchr(blob->current, 0, blob->end - blob->current); + + if (nul == NULL) { + blob->overrun = true; + return NULL; + } + + size = nul - blob->current + 1; + + assert(ensure_can_read(blob, size)); + + ret = (char *) blob->current; + + blob->current += size; + + return ret; +} diff --git a/lib/mesa/src/compiler/blob.h b/lib/mesa/src/compiler/blob.h new file mode 100644 index 000000000..2b975d45d --- /dev/null +++ b/lib/mesa/src/compiler/blob.h @@ -0,0 +1,352 @@ +/* + * Copyright © 2014 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. + */ + +#ifndef BLOB_H +#define BLOB_H + +#include <stdbool.h> +#include <stddef.h> +#include <stdint.h> +#include <stdlib.h> + +#ifdef __cplusplus +extern "C" { +#endif + +/* The blob functions implement a simple, low-level API for serializing and + * deserializing. + * + * All objects written to a blob will be serialized directly, (without any + * additional meta-data to describe the data written). Therefore, it is the + * caller's responsibility to ensure that any data can be read later, (either + * by knowing exactly what data is expected, or by writing to the blob + * sufficient meta-data to describe what has been written). + * + * A blob is efficient in that it dynamically grows by doubling in size, so + * allocation costs are logarithmic. + */ + +struct blob { + /* The data actually written to the blob. */ + uint8_t *data; + + /** Number of bytes that have been allocated for \c data. */ + size_t allocated; + + /** The number of bytes that have actual data written to them. */ + size_t size; + + /** True if \c data a fixed allocation that we cannot resize + * + * \see blob_init_fixed + */ + bool fixed_allocation; + + /** + * True if we've ever failed to realloc or if we go pas the end of a fixed + * allocation blob. + */ + bool out_of_memory; +}; + +/* When done reading, the caller can ensure that everything was consumed by + * checking the following: + * + * 1. blob->current should be equal to blob->end, (if not, too little was + * read). + * + * 2. blob->overrun should be false, (otherwise, too much was read). + */ +struct blob_reader { + const uint8_t *data; + const uint8_t *end; + const uint8_t *current; + bool overrun; +}; + +/** + * Init a new, empty blob. + */ +void +blob_init(struct blob *blob); + +/** + * Init a new, fixed-size blob. + * + * A fixed-size blob has a fixed block of data that will not be freed on + * blob_finish and will never be grown. If we hit the end, we simply start + * returning false from the write functions. + * + * If a fixed-size blob has a NULL data pointer then the data is written but + * it otherwise operates normally. This can be used to determine the size + * that will be required to write a given data structure. + */ +void +blob_init_fixed(struct blob *blob, void *data, size_t size); + +/** + * Finish a blob and free its memory. + * + * If \blob was initialized with blob_init_fixed, the data pointer is + * considered to be owned by the user and will not be freed. + */ +static inline void +blob_finish(struct blob *blob) +{ + if (!blob->fixed_allocation) + free(blob->data); +} + +/** + * Add some unstructured, fixed-size data to a blob. + * + * \return True unless allocation failed. + */ +bool +blob_write_bytes(struct blob *blob, const void *bytes, size_t to_write); + +/** + * Reserve space in \blob for a number of bytes. + * + * Space will be allocated within the blob for these byes, but the bytes will + * be left uninitialized. The caller is expected to use \sa + * blob_overwrite_bytes to write to these bytes. + * + * \return An offset to space allocated within \blob to which \to_write bytes + * can be written, (or -1 in case of any allocation error). + */ +intptr_t +blob_reserve_bytes(struct blob *blob, size_t to_write); + +/** + * Similar to \sa blob_reserve_bytes, but only reserves an uint32_t worth of + * space. Note that this must be used if later reading with \sa + * blob_read_uint32, since it aligns the offset correctly. + */ +intptr_t +blob_reserve_uint32(struct blob *blob); + +/** + * Similar to \sa blob_reserve_bytes, but only reserves an intptr_t worth of + * space. Note that this must be used if later reading with \sa + * blob_read_intptr, since it aligns the offset correctly. + */ +intptr_t +blob_reserve_intptr(struct blob *blob); + +/** + * Overwrite some data previously written to the blob. + * + * Writes data to an existing portion of the blob at an offset of \offset. + * This data range must have previously been written to the blob by one of the + * blob_write_* calls. + * + * For example usage, see blob_overwrite_uint32 + * + * \return True unless the requested offset or offset+to_write lie outside + * the current blob's size. + */ +bool +blob_overwrite_bytes(struct blob *blob, + size_t offset, + const void *bytes, + size_t to_write); + +/** + * Add a uint32_t to a blob. + * + * \note This function will only write to a uint32_t-aligned offset from the + * beginning of the blob's data, so some padding bytes may be added to the + * blob if this write follows some unaligned write (such as + * blob_write_string). + * + * \return True unless allocation failed. + */ +bool +blob_write_uint32(struct blob *blob, uint32_t value); + +/** + * Overwrite a uint32_t previously written to the blob. + * + * Writes a uint32_t value to an existing portion of the blob at an offset of + * \offset. This data range must have previously been written to the blob by + * one of the blob_write_* calls. + * + * + * The expected usage is something like the following pattern: + * + * size_t offset; + * + * offset = blob_reserve_uint32(blob); + * ... various blob write calls, writing N items ... + * blob_overwrite_uint32 (blob, offset, N); + * + * \return True unless the requested position or position+to_write lie outside + * the current blob's size. + */ +bool +blob_overwrite_uint32(struct blob *blob, + size_t offset, + uint32_t value); + +/** + * Add a uint64_t to a blob. + * + * \note This function will only write to a uint64_t-aligned offset from the + * beginning of the blob's data, so some padding bytes may be added to the + * blob if this write follows some unaligned write (such as + * blob_write_string). + * + * \return True unless allocation failed. + */ +bool +blob_write_uint64(struct blob *blob, uint64_t value); + +/** + * Add an intptr_t to a blob. + * + * \note This function will only write to an intptr_t-aligned offset from the + * beginning of the blob's data, so some padding bytes may be added to the + * blob if this write follows some unaligned write (such as + * blob_write_string). + * + * \return True unless allocation failed. + */ +bool +blob_write_intptr(struct blob *blob, intptr_t value); + +/** + * Overwrite an intptr_t previously written to the blob. + * + * Writes a intptr_t value to an existing portion of the blob at an offset of + * \offset. This data range must have previously been written to the blob by + * one of the blob_write_* calls. + * + * For example usage, see blob_overwrite_uint32 + * + * \return True unless the requested position or position+to_write lie outside + * the current blob's size. + */ +bool +blob_overwrite_intptr(struct blob *blob, + size_t offset, + intptr_t value); + +/** + * Add a NULL-terminated string to a blob, (including the NULL terminator). + * + * \return True unless allocation failed. + */ +bool +blob_write_string(struct blob *blob, const char *str); + +/** + * Start reading a blob, (initializing the contents of \blob for reading). + * + * After this call, the caller can use the various blob_read_* functions to + * read elements from the data array. + * + * For all of the blob_read_* functions, if there is insufficient data + * remaining, the functions will do nothing, (perhaps returning default values + * such as 0). The caller can detect this by noting that the blob_reader's + * current value is unchanged before and after the call. + */ +void +blob_reader_init(struct blob_reader *blob, const void *data, size_t size); + +/** + * Read some unstructured, fixed-size data from the current location, (and + * update the current location to just past this data). + * + * \note The memory returned belongs to the data underlying the blob reader. The + * caller must copy the data in order to use it after the lifetime of the data + * underlying the blob reader. + * + * \return The bytes read (see note above about memory lifetime). + */ +const void * +blob_read_bytes(struct blob_reader *blob, size_t size); + +/** + * Read some unstructured, fixed-size data from the current location, copying + * it to \dest (and update the current location to just past this data) + */ +void +blob_copy_bytes(struct blob_reader *blob, void *dest, size_t size); + +/** + * Read a uint32_t from the current location, (and update the current location + * to just past this uint32_t). + * + * \note This function will only read from a uint32_t-aligned offset from the + * beginning of the blob's data, so some padding bytes may be skipped. + * + * \return The uint32_t read + */ +uint32_t +blob_read_uint32(struct blob_reader *blob); + +/** + * Read a uint64_t from the current location, (and update the current location + * to just past this uint64_t). + * + * \note This function will only read from a uint64_t-aligned offset from the + * beginning of the blob's data, so some padding bytes may be skipped. + * + * \return The uint64_t read + */ +uint64_t +blob_read_uint64(struct blob_reader *blob); + +/** + * Read an intptr_t value from the current location, (and update the + * current location to just past this intptr_t). + * + * \note This function will only read from an intptr_t-aligned offset from the + * beginning of the blob's data, so some padding bytes may be skipped. + * + * \return The intptr_t read + */ +intptr_t +blob_read_intptr(struct blob_reader *blob); + +/** + * Read a NULL-terminated string from the current location, (and update the + * current location to just past this string). + * + * \note The memory returned belongs to the data underlying the blob reader. The + * caller must copy the string in order to use the string after the lifetime + * of the data underlying the blob reader. + * + * \return The string read (see note above about memory lifetime). However, if + * there is no NULL byte remaining within the blob, this function returns + * NULL. + */ +char * +blob_read_string(struct blob_reader *blob); + +#ifdef __cplusplus +} +#endif + +#endif /* BLOB_H */ diff --git a/lib/mesa/src/compiler/glsl/ir_expression_flattening.cpp b/lib/mesa/src/compiler/glsl/ir_expression_flattening.cpp index c13ae811d..e4ca850d2 100644 --- a/lib/mesa/src/compiler/glsl/ir_expression_flattening.cpp +++ b/lib/mesa/src/compiler/glsl/ir_expression_flattening.cpp @@ -77,9 +77,7 @@ ir_expression_flattening_visitor::handle_rvalue(ir_rvalue **rvalue) var = new(ctx) ir_variable(ir->type, "flattening_tmp", ir_var_temporary); base_ir->insert_before(var); - assign = new(ctx) ir_assignment(new(ctx) ir_dereference_variable(var), - ir, - NULL); + assign = new(ctx) ir_assignment(new(ctx) ir_dereference_variable(var), ir); base_ir->insert_before(assign); *rvalue = new(ctx) ir_dereference_variable(var); diff --git a/lib/mesa/src/compiler/glsl/loop_analysis.cpp b/lib/mesa/src/compiler/glsl/loop_analysis.cpp index b9bae4353..2979e0943 100644 --- a/lib/mesa/src/compiler/glsl/loop_analysis.cpp +++ b/lib/mesa/src/compiler/glsl/loop_analysis.cpp @@ -25,13 +25,188 @@ #include "loop_analysis.h" #include "ir_hierarchical_visitor.h" -static bool is_loop_terminator(ir_if *ir); +static void try_add_loop_terminator(loop_variable_state *ls, ir_if *ir); static bool all_expression_operands_are_loop_constant(ir_rvalue *, hash_table *); static ir_rvalue *get_basic_induction_increment(ir_assignment *, hash_table *); +/** + * Find an initializer of a variable outside a loop + * + * Works backwards from the loop to find the pre-loop value of the variable. + * This is used, for example, to find the initial value of loop induction + * variables. + * + * \param loop Loop where \c var is an induction variable + * \param var Variable whose initializer is to be found + * + * \return + * The \c ir_rvalue assigned to the variable outside the loop. May return + * \c NULL if no initializer can be found. + */ +static ir_rvalue * +find_initial_value(ir_loop *loop, ir_variable *var) +{ + for (exec_node *node = loop->prev; !node->is_head_sentinel(); + node = node->prev) { + ir_instruction *ir = (ir_instruction *) node; + + switch (ir->ir_type) { + case ir_type_call: + case ir_type_loop: + case ir_type_loop_jump: + case ir_type_return: + case ir_type_if: + return NULL; + + case ir_type_function: + case ir_type_function_signature: + assert(!"Should not get here."); + return NULL; + + case ir_type_assignment: { + ir_assignment *assign = ir->as_assignment(); + ir_variable *assignee = assign->lhs->whole_variable_referenced(); + + if (assignee == var) + return (assign->condition != NULL) ? NULL : assign->rhs; + + break; + } + + default: + break; + } + } + + return NULL; +} + + +static int +calculate_iterations(ir_rvalue *from, ir_rvalue *to, ir_rvalue *increment, + enum ir_expression_operation op, bool continue_from_then) +{ + if (from == NULL || to == NULL || increment == NULL) + return -1; + + void *mem_ctx = ralloc_context(NULL); + + ir_expression *const sub = + new(mem_ctx) ir_expression(ir_binop_sub, from->type, to, from); + + ir_expression *const div = + new(mem_ctx) ir_expression(ir_binop_div, sub->type, sub, increment); + + ir_constant *iter = div->constant_expression_value(mem_ctx); + if (iter == NULL) { + ralloc_free(mem_ctx); + return -1; + } + + if (!iter->type->is_integer()) { + const ir_expression_operation op = iter->type->is_double() + ? ir_unop_d2i : ir_unop_f2i; + ir_rvalue *cast = + new(mem_ctx) ir_expression(op, glsl_type::int_type, iter, NULL); + + iter = cast->constant_expression_value(mem_ctx); + } + + int iter_value = iter->get_int_component(0); + + /* Make sure that the calculated number of iterations satisfies the exit + * condition. This is needed to catch off-by-one errors and some types of + * ill-formed loops. For example, we need to detect that the following + * loop does not have a maximum iteration count. + * + * for (float x = 0.0; x != 0.9; x += 0.2) + * ; + */ + const int bias[] = { -1, 0, 1 }; + bool valid_loop = false; + + for (unsigned i = 0; i < ARRAY_SIZE(bias); i++) { + /* Increment may be of type int, uint or float. */ + switch (increment->type->base_type) { + case GLSL_TYPE_INT: + iter = new(mem_ctx) ir_constant(iter_value + bias[i]); + break; + case GLSL_TYPE_UINT: + iter = new(mem_ctx) ir_constant(unsigned(iter_value + bias[i])); + break; + case GLSL_TYPE_FLOAT: + iter = new(mem_ctx) ir_constant(float(iter_value + bias[i])); + break; + case GLSL_TYPE_DOUBLE: + iter = new(mem_ctx) ir_constant(double(iter_value + bias[i])); + break; + default: + unreachable("Unsupported type for loop iterator."); + } + + ir_expression *const mul = + new(mem_ctx) ir_expression(ir_binop_mul, increment->type, iter, + increment); + + ir_expression *const add = + new(mem_ctx) ir_expression(ir_binop_add, mul->type, mul, from); + + ir_expression *cmp = + new(mem_ctx) ir_expression(op, glsl_type::bool_type, add, to); + if (continue_from_then) + cmp = new(mem_ctx) ir_expression(ir_unop_logic_not, cmp); + + ir_constant *const cmp_result = cmp->constant_expression_value(mem_ctx); + + assert(cmp_result != NULL); + if (cmp_result->get_bool_component(0)) { + iter_value += bias[i]; + valid_loop = true; + break; + } + } + + ralloc_free(mem_ctx); + return (valid_loop) ? iter_value : -1; +} + +static bool +incremented_before_terminator(ir_loop *loop, ir_variable *var, + ir_if *terminator) +{ + for (exec_node *node = loop->body_instructions.get_head(); + !node->is_tail_sentinel(); + node = node->get_next()) { + ir_instruction *ir = (ir_instruction *) node; + + switch (ir->ir_type) { + case ir_type_if: + if (ir->as_if() == terminator) + return false; + break; + + case ir_type_assignment: { + ir_assignment *assign = ir->as_assignment(); + ir_variable *assignee = assign->lhs->whole_variable_referenced(); + + if (assignee == var) { + assert(assign->condition == NULL); + return true; + } + + break; + } + + default: + break; + } + } + + unreachable("Unable to find induction variable"); +} /** * Record the fact that the given loop variable was referenced inside the loop. @@ -133,12 +308,14 @@ loop_variable_state::insert(ir_variable *var) loop_terminator * -loop_variable_state::insert(ir_if *if_stmt) +loop_variable_state::insert(ir_if *if_stmt, bool continue_from_then) { void *mem_ctx = ralloc_parent(this); loop_terminator *t = new(mem_ctx) loop_terminator(); t->ir = if_stmt; + t->continue_from_then = continue_from_then; + this->terminators.push_tail(t); return t; @@ -295,10 +472,8 @@ loop_analysis::visit_leave(ir_loop *ir) ir_if *if_stmt = ((ir_instruction *) node)->as_if(); - if ((if_stmt != NULL) && is_loop_terminator(if_stmt)) - ls->insert(if_stmt); - else - break; + if (if_stmt != NULL) + try_add_loop_terminator(ls, if_stmt); } @@ -441,7 +616,11 @@ loop_analysis::visit_leave(ir_loop *ir) loop_variable *lv = ls->get(var); if (lv != NULL && lv->is_induction_var()) { t->iterations = calculate_iterations(init, limit, lv->increment, - cmp); + cmp, t->continue_from_then); + + if (incremented_before_terminator(ir, var, t->ir)) { + t->iterations--; + } if (t->iterations >= 0 && (ls->limiting_terminator == NULL || @@ -604,31 +783,26 @@ get_basic_induction_increment(ir_assignment *ir, hash_table *var_hash) /** - * Detect whether an if-statement is a loop terminating condition + * Detect whether an if-statement is a loop terminating condition, if so + * add it to the list of loop terminators. * * Detects if-statements of the form * - * (if (expression bool ...) (break)) + * (if (expression bool ...) (...then_instrs...break)) + * + * or + * + * (if (expression bool ...) ... (...else_instrs...break)) */ -bool -is_loop_terminator(ir_if *ir) +void +try_add_loop_terminator(loop_variable_state *ls, ir_if *ir) { - if (!ir->else_instructions.is_empty()) - return false; - - ir_instruction *const inst = - (ir_instruction *) ir->then_instructions.get_head(); - if (inst == NULL) - return false; - - if (inst->ir_type != ir_type_loop_jump) - return false; - - ir_loop_jump *const jump = (ir_loop_jump *) inst; - if (jump->mode != ir_loop_jump::jump_break) - return false; + ir_instruction *inst = (ir_instruction *) ir->then_instructions.get_tail(); + ir_instruction *else_inst = + (ir_instruction *) ir->else_instructions.get_tail(); - return true; + if (is_break(inst) || is_break(else_inst)) + ls->insert(ir, is_break(else_inst)); } diff --git a/lib/mesa/src/compiler/glsl/loop_unroll.cpp b/lib/mesa/src/compiler/glsl/loop_unroll.cpp index bc377dff3..874f41856 100644 --- a/lib/mesa/src/compiler/glsl/loop_unroll.cpp +++ b/lib/mesa/src/compiler/glsl/loop_unroll.cpp @@ -42,7 +42,9 @@ public: virtual ir_visitor_status visit_leave(ir_loop *ir); void simple_unroll(ir_loop *ir, int iterations); void complex_unroll(ir_loop *ir, int iterations, - bool continue_from_then_branch); + bool continue_from_then_branch, + bool limiting_term_first, + bool lt_continue_from_then_branch); void splice_post_if_instructions(ir_if *ir_if, exec_list *splice_dest); loop_state *state; @@ -53,13 +55,6 @@ public: } /* anonymous namespace */ -static bool -is_break(ir_instruction *ir) -{ - return ir != NULL && ir->ir_type == ir_type_loop_jump - && ((ir_loop_jump *) ir)->is_break(); -} - class loop_unroll_count : public ir_hierarchical_visitor { public: int nodes; @@ -106,7 +101,7 @@ public: if (options->EmitNoIndirectSampler) { if ((ir->array->type->is_array() && ir->array->type->contains_sampler()) && - !ir->array_index->constant_expression_value()) { + !ir->array_index->constant_expression_value(ralloc_parent(ir))) { unsupported_variable_indexing = true; return visit_continue; } @@ -183,6 +178,51 @@ void loop_unroll_visitor::simple_unroll(ir_loop *ir, int iterations) { void *const mem_ctx = ralloc_parent(ir); + loop_variable_state *const ls = this->state->get(ir); + + ir_instruction *first_ir = + (ir_instruction *) ir->body_instructions.get_head(); + + if (!first_ir) { + /* The loop is empty remove it and return */ + ir->remove(); + return; + } + + ir_if *limit_if = NULL; + bool exit_branch_has_instructions = false; + if (ls->limiting_terminator) { + limit_if = ls->limiting_terminator->ir; + ir_instruction *ir_if_last = (ir_instruction *) + limit_if->then_instructions.get_tail(); + + if (is_break(ir_if_last)) { + if (ir_if_last != limit_if->then_instructions.get_head()) + exit_branch_has_instructions = true; + + splice_post_if_instructions(limit_if, &limit_if->else_instructions); + ir_if_last->remove(); + } else { + ir_if_last = (ir_instruction *) + limit_if->else_instructions.get_tail(); + assert(is_break(ir_if_last)); + + if (ir_if_last != limit_if->else_instructions.get_head()) + exit_branch_has_instructions = true; + + splice_post_if_instructions(limit_if, &limit_if->then_instructions); + ir_if_last->remove(); + } + } + + /* Because 'iterations' is the number of times we pass over the *entire* + * loop body before hitting the first break, we need to bump the number of + * iterations if the limiting terminator is not the first instruction in + * the loop, or it the exit branch contains instructions. This ensures we + * execute any instructions before the terminator or in its exit branch. + */ + if (limit_if != first_ir->as_if() || exit_branch_has_instructions) + iterations++; for (int i = 0; i < iterations; i++) { exec_list copy_list; @@ -234,11 +274,22 @@ loop_unroll_visitor::simple_unroll(ir_loop *ir, int iterations) */ void loop_unroll_visitor::complex_unroll(ir_loop *ir, int iterations, - bool continue_from_then_branch) + bool second_term_then_continue, + bool extra_iteration_required, + bool first_term_then_continue) { void *const mem_ctx = ralloc_parent(ir); ir_instruction *ir_to_replace = ir; + /* Because 'iterations' is the number of times we pass over the *entire* + * loop body before hitting the first break, we need to bump the number of + * iterations if the limiting terminator is not the first instruction in + * the loop, or it the exit branch contains instructions. This ensures we + * execute any instructions before the terminator or in its exit branch. + */ + if (extra_iteration_required) + iterations++; + for (int i = 0; i < iterations; i++) { exec_list copy_list; @@ -248,6 +299,10 @@ loop_unroll_visitor::complex_unroll(ir_loop *ir, int iterations, ir_if *ir_if = ((ir_instruction *) copy_list.get_tail())->as_if(); assert(ir_if != NULL); + exec_list *const first_list = first_term_then_continue + ? &ir_if->then_instructions : &ir_if->else_instructions; + ir_if = ((ir_instruction *) first_list->get_tail())->as_if(); + ir_to_replace->insert_before(©_list); ir_to_replace->remove(); @@ -255,10 +310,10 @@ loop_unroll_visitor::complex_unroll(ir_loop *ir, int iterations, ir_to_replace = new(mem_ctx) ir_loop_jump(ir_loop_jump::jump_continue); - exec_list *const list = (continue_from_then_branch) + exec_list *const second_term_continue_list = second_term_then_continue ? &ir_if->then_instructions : &ir_if->else_instructions; - list->push_tail(ir_to_replace); + second_term_continue_list->push_tail(ir_to_replace); } ir_to_replace->remove(); @@ -300,12 +355,26 @@ loop_unroll_visitor::splice_post_if_instructions(ir_if *ir_if, } } +static bool +exit_branch_has_instructions(ir_if *term_if, bool lt_then_continue) +{ + if (lt_then_continue) { + if (term_if->else_instructions.get_head() == + term_if->else_instructions.get_tail()) + return false; + } else { + if (term_if->then_instructions.get_head() == + term_if->then_instructions.get_tail()) + return false; + } + + return true; +} ir_visitor_status loop_unroll_visitor::visit_leave(ir_loop *ir) { loop_variable_state *const ls = this->state->get(ir); - int iterations; /* If we've entered a loop that hasn't been analyzed, something really, * really bad has happened. @@ -315,6 +384,58 @@ loop_unroll_visitor::visit_leave(ir_loop *ir) return visit_continue; } + if (ls->limiting_terminator != NULL) { + /* If the limiting terminator has an iteration count of zero, then we've + * proven that the loop cannot run, so delete it. + */ + int iterations = ls->limiting_terminator->iterations; + if (iterations == 0) { + ir->remove(); + this->progress = true; + return visit_continue; + } + } + + /* Remove the conditional break statements associated with all terminators + * that are associated with a fixed iteration count, except for the one + * associated with the limiting terminator--that one needs to stay, since + * it terminates the loop. Exception: if the loop still has a normative + * bound, then that terminates the loop, so we don't even need the limiting + * terminator. + */ + foreach_in_list_safe(loop_terminator, t, &ls->terminators) { + if (t->iterations < 0) + continue; + + exec_list *branch_instructions; + if (t != ls->limiting_terminator) { + ir_instruction *ir_if_last = (ir_instruction *) + t->ir->then_instructions.get_tail(); + if (is_break(ir_if_last)) { + branch_instructions = &t->ir->else_instructions; + } else { + branch_instructions = &t->ir->then_instructions; + assert(is_break((ir_instruction *) + t->ir->else_instructions.get_tail())); + } + + exec_list copy_list; + copy_list.make_empty(); + clone_ir_list(ir, ©_list, branch_instructions); + + t->ir->insert_before(©_list); + t->ir->remove(); + + assert(ls->num_loop_jumps > 0); + ls->num_loop_jumps--; + + /* Also remove it from the terminator list */ + t->remove(); + + this->progress = true; + } + } + if (ls->limiting_terminator == NULL) { ir_instruction *last_ir = (ir_instruction *) ir->body_instructions.get_tail(); @@ -343,7 +464,7 @@ loop_unroll_visitor::visit_leave(ir_loop *ir) return visit_continue; } - iterations = ls->limiting_terminator->iterations; + int iterations = ls->limiting_terminator->iterations; const int max_iterations = options->MaxUnrollIterations; @@ -373,7 +494,6 @@ loop_unroll_visitor::visit_leave(ir_loop *ir) return visit_continue; if (predicted_num_loop_jumps == 0) { - ls->limiting_terminator->ir->remove(); simple_unroll(ir, iterations); return visit_continue; } @@ -388,51 +508,69 @@ loop_unroll_visitor::visit_leave(ir_loop *ir) */ last_ir->remove(); - ls->limiting_terminator->ir->remove(); simple_unroll(ir, 1); return visit_continue; } - /* recognize loops in the form produced by ir_lower_jumps */ - foreach_in_list(ir_instruction, cur_ir, &ir->body_instructions) { - /* Skip the limiting terminator, since it will go away when we - * unroll. - */ - if (cur_ir == ls->limiting_terminator->ir) - continue; + /* Complex unrolling can only handle two terminators. One with an unknown + * iteration count and one with a known iteration count. We have already + * made sure we have a known iteration count above and removed any + * unreachable terminators with a known count. Here we make sure there + * isn't any additional unknown terminators, or any other jumps nested + * inside futher ifs. + */ + if (ls->num_loop_jumps != 2 || ls->terminators.length() != 2) + return visit_continue; + + ir_instruction *first_ir = + (ir_instruction *) ir->body_instructions.get_head(); - ir_if *ir_if = cur_ir->as_if(); - if (ir_if != NULL) { - /* Determine which if-statement branch, if any, ends with a - * break. The branch that did *not* have the break will get a - * temporary continue inserted in each iteration of the loop - * unroll. - * - * Note that since ls->num_loop_jumps is <= 1, it is impossible - * for both branches to end with a break. - */ - ir_instruction *ir_if_last = - (ir_instruction *) ir_if->then_instructions.get_tail(); + unsigned term_count = 0; + bool first_term_then_continue = false; + foreach_in_list(loop_terminator, t, &ls->terminators) { + ir_if *ir_if = t->ir->as_if(); + assert(ir_if != NULL); + ir_instruction *ir_if_last = + (ir_instruction *) ir_if->then_instructions.get_tail(); + + if (is_break(ir_if_last)) { + splice_post_if_instructions(ir_if, &ir_if->else_instructions); + ir_if_last->remove(); + if (term_count == 1) { + bool ebi = + exit_branch_has_instructions(ls->limiting_terminator->ir, + first_term_then_continue); + complex_unroll(ir, iterations, false, + first_ir->as_if() != ls->limiting_terminator->ir || + ebi, + first_term_then_continue); + return visit_continue; + } + } else { + ir_if_last = + (ir_instruction *) ir_if->else_instructions.get_tail(); + + assert(is_break(ir_if_last)); if (is_break(ir_if_last)) { - ls->limiting_terminator->ir->remove(); - splice_post_if_instructions(ir_if, &ir_if->else_instructions); + splice_post_if_instructions(ir_if, &ir_if->then_instructions); ir_if_last->remove(); - complex_unroll(ir, iterations, false); - return visit_continue; - } else { - ir_if_last = - (ir_instruction *) ir_if->else_instructions.get_tail(); - - if (is_break(ir_if_last)) { - ls->limiting_terminator->ir->remove(); - splice_post_if_instructions(ir_if, &ir_if->then_instructions); - ir_if_last->remove(); - complex_unroll(ir, iterations, true); + if (term_count == 1) { + bool ebi = + exit_branch_has_instructions(ls->limiting_terminator->ir, + first_term_then_continue); + complex_unroll(ir, iterations, true, + first_ir->as_if() != ls->limiting_terminator->ir || + ebi, + first_term_then_continue); return visit_continue; + } else { + first_term_then_continue = true; } } } + + term_count++; } /* Did not find the break statement. It must be in a complex if-nesting, diff --git a/lib/mesa/src/compiler/glsl/lower_discard.cpp b/lib/mesa/src/compiler/glsl/lower_discard.cpp index b62eb20dc..203d9e3b9 100644 --- a/lib/mesa/src/compiler/glsl/lower_discard.cpp +++ b/lib/mesa/src/compiler/glsl/lower_discard.cpp @@ -158,7 +158,7 @@ replace_discard(void *mem_ctx, ir_variable *var, ir_discard *ir) ir_assignment *assignment = new(mem_ctx) ir_assignment(new(mem_ctx) ir_dereference_variable(var), - condition, NULL); + condition); ir->replace_with(assignment); } @@ -180,7 +180,7 @@ lower_discard_visitor::visit_leave(ir_if *ir) ir_var_temporary); ir_assignment *temp_initializer = new(mem_ctx) ir_assignment(new(mem_ctx) ir_dereference_variable(temp), - new(mem_ctx) ir_constant(false), NULL); + new(mem_ctx) ir_constant(false)); ir->insert_before(temp); ir->insert_before(temp_initializer); diff --git a/lib/mesa/src/compiler/glsl/lower_mat_op_to_vec.cpp b/lib/mesa/src/compiler/glsl/lower_mat_op_to_vec.cpp index 9a27029de..88c5d6679 100644 --- a/lib/mesa/src/compiler/glsl/lower_mat_op_to_vec.cpp +++ b/lib/mesa/src/compiler/glsl/lower_mat_op_to_vec.cpp @@ -76,7 +76,7 @@ mat_op_to_vec_predicate(ir_instruction *ir) if (!expr) return false; - for (i = 0; i < expr->get_num_operands(); i++) { + for (i = 0; i < expr->num_operands; i++) { if (expr->operands[i]->type->is_matrix()) return true; } @@ -294,7 +294,7 @@ ir_mat_op_to_vec_visitor::do_equal_mat_mat(ir_dereference *result, static bool has_matrix_operand(const ir_expression *expr, unsigned &columns) { - for (unsigned i = 0; i < expr->get_num_operands(); i++) { + for (unsigned i = 0; i < expr->num_operands; i++) { if (expr->operands[i]->type->is_matrix()) { columns = expr->operands[i]->type->matrix_columns; return true; @@ -318,7 +318,7 @@ ir_mat_op_to_vec_visitor::visit_leave(ir_assignment *orig_assign) if (!has_matrix_operand(orig_expr, matrix_columns)) return visit_continue; - assert(orig_expr->get_num_operands() <= 2); + assert(orig_expr->num_operands <= 2); mem_ctx = ralloc_parent(orig_assign); @@ -329,7 +329,7 @@ ir_mat_op_to_vec_visitor::visit_leave(ir_assignment *orig_assign) /* Store the expression operands in temps so we can use them * multiple times. */ - for (i = 0; i < orig_expr->get_num_operands(); i++) { + for (i = 0; i < orig_expr->num_operands; i++) { ir_assignment *assign; ir_dereference *deref = orig_expr->operands[i]->as_dereference(); diff --git a/lib/mesa/src/compiler/glsl/lower_shared_reference.cpp b/lib/mesa/src/compiler/glsl/lower_shared_reference.cpp index b9098913a..a1b3f7df4 100644 --- a/lib/mesa/src/compiler/glsl/lower_shared_reference.cpp +++ b/lib/mesa/src/compiler/glsl/lower_shared_reference.cpp @@ -33,6 +33,7 @@ #include "lower_buffer_access.h" #include "ir_builder.h" +#include "linker.h" #include "main/macros.h" #include "util/list.h" #include "glsl_parser_extras.h" @@ -478,7 +479,9 @@ lower_shared_reference_visitor::visit_enter(ir_call *ir) } /* unnamed namespace */ void -lower_shared_reference(struct gl_linked_shader *shader, unsigned *shared_size) +lower_shared_reference(struct gl_context *ctx, + struct gl_shader_program *prog, + struct gl_linked_shader *shader) { if (shader->Stage != MESA_SHADER_COMPUTE) return; @@ -495,5 +498,19 @@ lower_shared_reference(struct gl_linked_shader *shader, unsigned *shared_size) visit_list_elements(&v, shader->ir); } while (v.progress); - *shared_size = v.shared_size; + prog->Comp.SharedSize = v.shared_size; + + /* Section 19.1 (Compute Shader Variables) of the OpenGL 4.5 (Core Profile) + * specification says: + * + * "There is a limit to the total size of all variables declared as + * shared in a single program object. This limit, expressed in units of + * basic machine units, may be queried as the value of + * MAX_COMPUTE_SHARED_MEMORY_SIZE." + */ + if (prog->Comp.SharedSize > ctx->Const.MaxComputeSharedMemorySize) { + linker_error(prog, "Too much shared memory used (%u/%u)\n", + prog->Comp.SharedSize, + ctx->Const.MaxComputeSharedMemorySize); + } } diff --git a/lib/mesa/src/compiler/glsl/lower_tess_level.cpp b/lib/mesa/src/compiler/glsl/lower_tess_level.cpp index 0a244f143..b0965eb56 100644 --- a/lib/mesa/src/compiler/glsl/lower_tess_level.cpp +++ b/lib/mesa/src/compiler/glsl/lower_tess_level.cpp @@ -264,7 +264,8 @@ lower_tess_level_visitor::fix_lhs(ir_assignment *ir) ir_dereference *const new_lhs = (ir_dereference *) expr->operands[0]; - ir_constant *old_index_constant = expr->operands[1]->constant_expression_value(); + ir_constant *old_index_constant = + expr->operands[1]->constant_expression_value(mem_ctx); if (!old_index_constant) { ir->rhs = new(mem_ctx) ir_expression(ir_triop_vector_insert, expr->operands[0]->type, diff --git a/lib/mesa/src/compiler/glsl/lower_variable_index_to_cond_assign.cpp b/lib/mesa/src/compiler/glsl/lower_variable_index_to_cond_assign.cpp index fcb12d1b7..6fe4fe62b 100644 --- a/lib/mesa/src/compiler/glsl/lower_variable_index_to_cond_assign.cpp +++ b/lib/mesa/src/compiler/glsl/lower_variable_index_to_cond_assign.cpp @@ -51,6 +51,10 @@ #include "ir_optimization.h" #include "compiler/glsl_types.h" #include "main/macros.h" +#include "program/prog_instruction.h" /* For SWIZZLE_XXXX */ +#include "ir_builder.h" + +using namespace ir_builder; /** * Generate a comparison value for a block of indices @@ -66,23 +70,21 @@ * \param mem_ctx ralloc memory context to be used for all allocations. * * \returns - * An \c ir_rvalue that \b must be cloned for each use in conditional - * assignments, etc. + * An \c ir_variable containing the per-component comparison results. This + * must be dereferenced per use. */ -ir_rvalue * -compare_index_block(exec_list *instructions, ir_variable *index, - unsigned base, unsigned components, void *mem_ctx) +ir_variable * +compare_index_block(ir_factory &body, ir_variable *index, + unsigned base, unsigned components) { - ir_rvalue *broadcast_index = new(mem_ctx) ir_dereference_variable(index); - assert(index->type->is_scalar()); - assert(index->type->base_type == GLSL_TYPE_INT || index->type->base_type == GLSL_TYPE_UINT); + assert(index->type->base_type == GLSL_TYPE_INT || + index->type->base_type == GLSL_TYPE_UINT); assert(components >= 1 && components <= 4); - if (components > 1) { - const ir_swizzle_mask m = { 0, 0, 0, 0, components, false }; - broadcast_index = new(mem_ctx) ir_swizzle(broadcast_index, m); - } + ir_rvalue *const broadcast_index = components > 1 + ? swizzle(index, SWIZZLE_XXXX, components) + : operand(index).val; /* Compare the desired index value with the next block of four indices. */ @@ -94,26 +96,16 @@ compare_index_block(exec_list *instructions, ir_variable *index, test_indices_data.i[3] = base + 3; ir_constant *const test_indices = - new(mem_ctx) ir_constant(broadcast_index->type, - &test_indices_data); - - ir_rvalue *const condition_val = - new(mem_ctx) ir_expression(ir_binop_equal, - glsl_type::bvec(components), - broadcast_index, - test_indices); - - ir_variable *const condition = - new(mem_ctx) ir_variable(condition_val->type, - "dereference_condition", - ir_var_temporary); - instructions->push_tail(condition); - - ir_rvalue *const cond_deref = - new(mem_ctx) ir_dereference_variable(condition); - instructions->push_tail(new(mem_ctx) ir_assignment(cond_deref, condition_val, 0)); - - return cond_deref; + new(body.mem_ctx) ir_constant(broadcast_index->type, &test_indices_data); + + ir_rvalue *const condition_val = equal(broadcast_index, test_indices); + + ir_variable *const condition = body.make_temp(condition_val->type, + "dereference_condition"); + + body.emit(assign(condition, condition_val)); + + return condition; } static inline bool @@ -133,7 +125,7 @@ class deref_replacer : public ir_rvalue_visitor { public: deref_replacer(const ir_variable *variable_to_replace, ir_rvalue *value) : variable_to_replace(variable_to_replace), value(value), - progress(false) + progress(false) { assert(this->variable_to_replace != NULL); assert(this->value != NULL); @@ -143,9 +135,9 @@ public: { ir_dereference_variable *const dv = (*rvalue)->as_dereference_variable(); - if ((dv != NULL) && (dv->var == this->variable_to_replace)) { - this->progress = true; - *rvalue = this->value->clone(ralloc_parent(*rvalue), NULL); + if (dv != NULL && dv->var == this->variable_to_replace) { + this->progress = true; + *rvalue = this->value->clone(ralloc_parent(*rvalue), NULL); } } @@ -167,10 +159,10 @@ public: virtual ir_visitor_status visit_enter(ir_dereference_array *ir) { - if (is_array_or_matrix(ir->array) - && (ir->array_index->as_constant() == NULL)) { - this->deref = ir; - return visit_stop; + if (is_array_or_matrix(ir->array) && + ir->array_index->as_constant() == NULL) { + this->deref = ir; + return visit_stop; } return visit_continue; @@ -201,18 +193,13 @@ struct assignment_generator { } - void generate(unsigned i, ir_rvalue* condition, exec_list *list) const + void generate(unsigned i, ir_rvalue* condition, ir_factory &body) const { - /* Just clone the rest of the deref chain when trying to get at the - * underlying variable. - */ - void *mem_ctx = ralloc_parent(base_ir); - /* Clone the old r-value in its entirety. Then replace any occurances of * the old variable index with the new constant index. */ - ir_dereference *element = this->rvalue->clone(mem_ctx, NULL); - ir_constant *const index = new(mem_ctx) ir_constant(i); + ir_dereference *element = this->rvalue->clone(body.mem_ctx, NULL); + ir_constant *const index = body.constant(i); deref_replacer r(this->old_index, index); element->accept(&r); assert(r.progress); @@ -220,12 +207,11 @@ struct assignment_generator /* Generate a conditional assignment to (or from) the constant indexed * array dereference. */ - ir_rvalue *variable = new(mem_ctx) ir_dereference_variable(this->var); ir_assignment *const assignment = (is_write) - ? new(mem_ctx) ir_assignment(element, variable, condition, write_mask) - : new(mem_ctx) ir_assignment(variable, element, condition); + ? assign(element, this->var, condition, write_mask) + : assign(this->var, element, condition); - list->push_tail(assignment); + body.emit(assignment); } }; @@ -242,16 +228,16 @@ struct switch_generator void *mem_ctx; switch_generator(const TFunction& generator, ir_variable *index, - unsigned linear_sequence_max_length, - unsigned condition_components) + unsigned linear_sequence_max_length, + unsigned condition_components) : generator(generator), index(index), - linear_sequence_max_length(linear_sequence_max_length), - condition_components(condition_components) + linear_sequence_max_length(linear_sequence_max_length), + condition_components(condition_components) { this->mem_ctx = ralloc_parent(index); } - void linear_sequence(unsigned begin, unsigned end, exec_list *list) + void linear_sequence(unsigned begin, unsigned end, ir_factory &body) { if (begin == end) return; @@ -266,66 +252,57 @@ struct switch_generator */ unsigned first; if (!this->generator.is_write) { - this->generator.generate(begin, 0, list); - first = begin + 1; + this->generator.generate(begin, 0, body); + first = begin + 1; } else { - first = begin; + first = begin; } for (unsigned i = first; i < end; i += 4) { const unsigned comps = MIN2(condition_components, end - i); - - ir_rvalue *const cond_deref = - compare_index_block(list, index, i, comps, this->mem_ctx); + ir_variable *const cond = compare_index_block(body, index, i, comps); if (comps == 1) { - this->generator.generate(i, cond_deref->clone(this->mem_ctx, NULL), - list); + this->generator.generate(i, + operand(cond).val, + body); } else { for (unsigned j = 0; j < comps; j++) { - ir_rvalue *const cond_swiz = - new(this->mem_ctx) ir_swizzle(cond_deref->clone(this->mem_ctx, NULL), - j, 0, 0, 0, 1); - - this->generator.generate(i + j, cond_swiz, list); + this->generator.generate(i + j, + swizzle(cond, j, 1), + body); } } } } - void bisect(unsigned begin, unsigned end, exec_list *list) + void bisect(unsigned begin, unsigned end, ir_factory &body) { unsigned middle = (begin + end) >> 1; assert(index->type->is_integer()); ir_constant *const middle_c = (index->type->base_type == GLSL_TYPE_UINT) - ? new(this->mem_ctx) ir_constant((unsigned)middle) - : new(this->mem_ctx) ir_constant((int)middle); - - - ir_dereference_variable *deref = - new(this->mem_ctx) ir_dereference_variable(this->index); + ? new(body.mem_ctx) ir_constant((unsigned)middle) + : new(body.mem_ctx) ir_constant((int)middle); - ir_expression *less = - new(this->mem_ctx) ir_expression(ir_binop_less, glsl_type::bool_type, - deref, middle_c); + ir_if *if_less = new(body.mem_ctx) ir_if(less(this->index, middle_c)); - ir_if *if_less = new(this->mem_ctx) ir_if(less); + ir_factory then_body(&if_less->then_instructions, body.mem_ctx); + ir_factory else_body(&if_less->else_instructions, body.mem_ctx); + generate(begin, middle, then_body); + generate(middle, end, else_body); - generate(begin, middle, &if_less->then_instructions); - generate(middle, end, &if_less->else_instructions); - - list->push_tail(if_less); + body.emit(if_less); } - void generate(unsigned begin, unsigned end, exec_list *list) + void generate(unsigned begin, unsigned end, ir_factory &body) { unsigned length = end - begin; if (length <= this->linear_sequence_max_length) - return linear_sequence(begin, end, list); + return linear_sequence(begin, end, body); else - return bisect(begin, end, list); + return bisect(begin, end, body); } }; @@ -340,13 +317,11 @@ public: bool lower_output, bool lower_temp, bool lower_uniform) + : progress(false), stage(stage), lower_inputs(lower_input), + lower_outputs(lower_output), lower_temps(lower_temp), + lower_uniforms(lower_uniform) { - this->progress = false; - this->stage = stage; - this->lower_inputs = lower_input; - this->lower_outputs = lower_output; - this->lower_temps = lower_temp; - this->lower_uniforms = lower_uniform; + /* empty */ } bool progress; @@ -367,19 +342,19 @@ public: */ const ir_variable *const var = deref->array->variable_referenced(); if (var == NULL) - return this->lower_temps; + return this->lower_temps; switch (var->data.mode) { case ir_var_auto: case ir_var_temporary: - return this->lower_temps; + return this->lower_temps; case ir_var_uniform: case ir_var_shader_storage: - return this->lower_uniforms; + return this->lower_uniforms; case ir_var_shader_shared: - return false; + return false; case ir_var_function_in: case ir_var_const_in: @@ -435,7 +410,7 @@ public: return this->lower_outputs; case ir_var_function_inout: - return this->lower_temps; + return this->lower_temps; } assert(!"Should not get here."); @@ -444,25 +419,27 @@ public: bool needs_lowering(ir_dereference_array *deref) const { - if (deref == NULL || deref->array_index->as_constant() - || !is_array_or_matrix(deref->array)) - return false; + if (deref == NULL || deref->array_index->as_constant() || + !is_array_or_matrix(deref->array)) + return false; return this->storage_type_needs_lowering(deref); } ir_variable *convert_dereference_array(ir_dereference_array *orig_deref, - ir_assignment* orig_assign, - ir_dereference *orig_base) + ir_assignment* orig_assign, + ir_dereference *orig_base) { + void *const mem_ctx = ralloc_parent(base_ir); + exec_list list; + ir_factory body(&list, mem_ctx); + assert(is_array_or_matrix(orig_deref->array)); const unsigned length = (orig_deref->array->type->is_array()) ? orig_deref->array->type->length : orig_deref->array->type->matrix_columns; - void *const mem_ctx = ralloc_parent(base_ir); - /* Temporary storage for either the result of the dereference of * the array, or the RHS that's being assigned into the * dereference of the array. @@ -470,36 +447,22 @@ public: ir_variable *var; if (orig_assign) { - var = new(mem_ctx) ir_variable(orig_assign->rhs->type, - "dereference_array_value", - ir_var_temporary); - base_ir->insert_before(var); + var = body.make_temp(orig_assign->rhs->type, + "dereference_array_value"); - ir_dereference *lhs = new(mem_ctx) ir_dereference_variable(var); - ir_assignment *assign = new(mem_ctx) ir_assignment(lhs, - orig_assign->rhs, - NULL); - - base_ir->insert_before(assign); + body.emit(assign(var, orig_assign->rhs)); } else { - var = new(mem_ctx) ir_variable(orig_deref->type, - "dereference_array_value", - ir_var_temporary); - base_ir->insert_before(var); + var = body.make_temp(orig_deref->type, + "dereference_array_value"); } /* Store the index to a temporary to avoid reusing its tree. */ - ir_variable *index = - new(mem_ctx) ir_variable(orig_deref->array_index->type, - "dereference_array_index", ir_var_temporary); - base_ir->insert_before(index); + ir_variable *index = body.make_temp(orig_deref->array_index->type, + "dereference_array_index"); - ir_dereference *lhs = new(mem_ctx) ir_dereference_variable(index); - ir_assignment *assign = - new(mem_ctx) ir_assignment(lhs, orig_deref->array_index, NULL); - base_ir->insert_before(assign); + body.emit(assign(index, orig_deref->array_index)); - orig_deref->array_index = lhs->clone(mem_ctx, NULL); + orig_deref->array_index = deref(index).val; assignment_generator ag; ag.rvalue = orig_base; @@ -507,10 +470,10 @@ public: ag.old_index = index; ag.var = var; if (orig_assign) { - ag.is_write = true; - ag.write_mask = orig_assign->write_mask; + ag.is_write = true; + ag.write_mask = orig_assign->write_mask; } else { - ag.is_write = false; + ag.is_write = false; } switch_generator sg(ag, index, 4, 4); @@ -519,28 +482,27 @@ public: * condition! This is acomplished by wrapping the new conditional * assignments in an if-statement that uses the original condition. */ - if ((orig_assign != NULL) && (orig_assign->condition != NULL)) { - /* No need to clone the condition because the IR that it hangs on is - * going to be removed from the instruction sequence. - */ - ir_if *if_stmt = new(mem_ctx) ir_if(orig_assign->condition); - - sg.generate(0, length, &if_stmt->then_instructions); - base_ir->insert_before(if_stmt); - } else { - exec_list list; + if (orig_assign != NULL && orig_assign->condition != NULL) { + /* No need to clone the condition because the IR that it hangs on is + * going to be removed from the instruction sequence. + */ + ir_if *if_stmt = new(mem_ctx) ir_if(orig_assign->condition); + ir_factory then_body(&if_stmt->then_instructions, body.mem_ctx); - sg.generate(0, length, &list); - base_ir->insert_before(&list); + sg.generate(0, length, then_body); + body.emit(if_stmt); + } else { + sg.generate(0, length, body); } + base_ir->insert_before(&list); return var; } virtual void handle_rvalue(ir_rvalue **pir) { if (this->in_assignee) - return; + return; if (!*pir) return; @@ -548,7 +510,7 @@ public: ir_dereference_array* orig_deref = (*pir)->as_dereference_array(); if (needs_lowering(orig_deref)) { ir_variable *var = - convert_dereference_array(orig_deref, NULL, orig_deref); + convert_dereference_array(orig_deref, NULL, orig_deref); assert(var); *pir = new(ralloc_parent(base_ir)) ir_dereference_variable(var); this->progress = true; @@ -563,7 +525,7 @@ public: find_variable_index f; ir->lhs->accept(&f); - if ((f.deref != NULL) && storage_type_needs_lowering(f.deref)) { + if (f.deref != NULL && storage_type_needs_lowering(f.deref)) { convert_dereference_array(f.deref, ir, ir->lhs); ir->remove(); this->progress = true; diff --git a/lib/mesa/src/compiler/glsl/lower_vec_index_to_swizzle.cpp b/lib/mesa/src/compiler/glsl/lower_vec_index_to_swizzle.cpp index b49255e05..fdbad16a3 100644 --- a/lib/mesa/src/compiler/glsl/lower_vec_index_to_swizzle.cpp +++ b/lib/mesa/src/compiler/glsl/lower_vec_index_to_swizzle.cpp @@ -63,11 +63,12 @@ ir_vec_index_to_swizzle_visitor::handle_rvalue(ir_rvalue **rv) if (expr == NULL || expr->operation != ir_binop_vector_extract) return; - ir_constant *const idx = expr->operands[1]->constant_expression_value(); + void *mem_ctx = ralloc_parent(expr); + ir_constant *const idx = + expr->operands[1]->constant_expression_value(mem_ctx); if (idx == NULL) return; - void *ctx = ralloc_parent(expr); this->progress = true; /* Page 40 of the GLSL 1.20 spec says: @@ -87,7 +88,7 @@ ir_vec_index_to_swizzle_visitor::handle_rvalue(ir_rvalue **rv) const int i = CLAMP(idx->value.i[0], 0, (int) expr->operands[0]->type->vector_elements - 1); - *rv = new(ctx) ir_swizzle(expr->operands[0], i, 0, 0, 0, 1); + *rv = new(mem_ctx) ir_swizzle(expr->operands[0], i, 0, 0, 0, 1); } bool diff --git a/lib/mesa/src/compiler/glsl/lower_vector.cpp b/lib/mesa/src/compiler/glsl/lower_vector.cpp index a658410ae..4024644b0 100644 --- a/lib/mesa/src/compiler/glsl/lower_vector.cpp +++ b/lib/mesa/src/compiler/glsl/lower_vector.cpp @@ -58,7 +58,7 @@ public: * Extended swizzles consist of access of a single vector source (with possible * per component negation) and the constants -1, 0, or 1. */ -bool +static bool is_extended_swizzle(ir_expression *ir) { /* Track any variables that are accessed by this expression. @@ -133,7 +133,7 @@ lower_vector_visitor::handle_rvalue(ir_rvalue **rvalue) */ void *const mem_ctx = expr; - assert(expr->type->vector_elements == expr->get_num_operands()); + assert(expr->type->vector_elements == expr->num_operands); /* Generate a temporary with the same type as the ir_quadop_operation. */ diff --git a/lib/mesa/src/compiler/glsl/lower_vector_derefs.cpp b/lib/mesa/src/compiler/glsl/lower_vector_derefs.cpp index f7bf68db3..a83658d20 100644 --- a/lib/mesa/src/compiler/glsl/lower_vector_derefs.cpp +++ b/lib/mesa/src/compiler/glsl/lower_vector_derefs.cpp @@ -61,8 +61,9 @@ vector_deref_visitor::visit_enter(ir_assignment *ir) ir_dereference *const new_lhs = (ir_dereference *) deref->array; ir->set_lhs(new_lhs); - ir_constant *old_index_constant = deref->array_index->constant_expression_value(); void *mem_ctx = ralloc_parent(ir); + ir_constant *old_index_constant = + deref->array_index->constant_expression_value(mem_ctx); if (!old_index_constant) { ir->rhs = new(mem_ctx) ir_expression(ir_triop_vector_insert, new_lhs->type, diff --git a/lib/mesa/src/compiler/glsl/lower_vector_insert.cpp b/lib/mesa/src/compiler/glsl/lower_vector_insert.cpp index 26d31b03c..ceaa5887c 100644 --- a/lib/mesa/src/compiler/glsl/lower_vector_insert.cpp +++ b/lib/mesa/src/compiler/glsl/lower_vector_insert.cpp @@ -65,7 +65,8 @@ vector_insert_visitor::handle_rvalue(ir_rvalue **rv) factory.mem_ctx = ralloc_parent(expr); - ir_constant *const idx = expr->operands[2]->constant_expression_value(); + ir_constant *const idx = + expr->operands[2]->constant_expression_value(factory.mem_ctx); if (idx != NULL) { /* Replace (vector_insert (vec) (scalar) (index)) with a dereference of * a new temporary. The new temporary gets assigned as diff --git a/lib/mesa/src/compiler/glsl/opt_constant_folding.cpp b/lib/mesa/src/compiler/glsl/opt_constant_folding.cpp index 97dcc7e1a..3b9394d13 100644 --- a/lib/mesa/src/compiler/glsl/opt_constant_folding.cpp +++ b/lib/mesa/src/compiler/glsl/opt_constant_folding.cpp @@ -74,7 +74,7 @@ ir_constant_fold(ir_rvalue **rvalue) */ ir_expression *expr = (*rvalue)->as_expression(); if (expr) { - for (unsigned int i = 0; i < expr->get_num_operands(); i++) { + for (unsigned int i = 0; i < expr->num_operands; i++) { if (!expr->operands[i]->as_constant()) return false; } @@ -100,7 +100,8 @@ ir_constant_fold(ir_rvalue **rvalue) if (var_ref) return false; - ir_constant *constant = (*rvalue)->constant_expression_value(); + ir_constant *constant = + (*rvalue)->constant_expression_value(ralloc_parent(*rvalue)); if (constant) { *rvalue = constant; return true; @@ -189,7 +190,7 @@ ir_constant_folding_visitor::visit_enter(ir_call *ir) } /* Next, see if the call can be replaced with an assignment of a constant */ - ir_constant *const_val = ir->constant_expression_value(); + ir_constant *const_val = ir->constant_expression_value(ralloc_parent(ir)); if (const_val != NULL) { ir_assignment *assignment = diff --git a/lib/mesa/src/compiler/glsl/opt_constant_variable.cpp b/lib/mesa/src/compiler/glsl/opt_constant_variable.cpp index 1c06ffe67..914b46004 100644 --- a/lib/mesa/src/compiler/glsl/opt_constant_variable.cpp +++ b/lib/mesa/src/compiler/glsl/opt_constant_variable.cpp @@ -131,7 +131,7 @@ ir_constant_variable_visitor::visit_enter(ir_assignment *ir) var->data.mode == ir_var_shader_shared) return visit_continue; - constval = ir->rhs->constant_expression_value(); + constval = ir->rhs->constant_expression_value(ralloc_parent(ir)); if (!constval) return visit_continue; diff --git a/lib/mesa/src/compiler/glsl/opt_if_simplification.cpp b/lib/mesa/src/compiler/glsl/opt_if_simplification.cpp index e05f03190..136ef8772 100644 --- a/lib/mesa/src/compiler/glsl/opt_if_simplification.cpp +++ b/lib/mesa/src/compiler/glsl/opt_if_simplification.cpp @@ -84,7 +84,8 @@ ir_if_simplification_visitor::visit_leave(ir_if *ir) * FINISHME: This can probably be done with some flags, but it would take * FINISHME: some work to get right. */ - ir_constant *condition_constant = ir->condition->constant_expression_value(); + ir_constant *condition_constant = + ir->condition->constant_expression_value(ralloc_parent(ir)); if (condition_constant) { /* Move the contents of the one branch of the conditional * that matters out. diff --git a/lib/mesa/src/compiler/glsl/tests/array_refcount_test.cpp b/lib/mesa/src/compiler/glsl/tests/array_refcount_test.cpp index ecd7f4690..0d8f4521c 100644 --- a/lib/mesa/src/compiler/glsl/tests/array_refcount_test.cpp +++ b/lib/mesa/src/compiler/glsl/tests/array_refcount_test.cpp @@ -628,7 +628,7 @@ TEST_F(array_refcount_test, visit_array_indexing_an_array) ir_array_refcount_entry *const entry_c = v.get_variable_entry(var_c); - for (unsigned i = 0; i < var_c->type->array_size(); i++) { + for (int i = 0; i < var_c->type->array_size(); i++) { EXPECT_EQ(true, entry_c->is_linearized_index_referenced(i)) << "array c, i = " << i; } diff --git a/lib/mesa/src/compiler/glsl/tests/meson.build b/lib/mesa/src/compiler/glsl/tests/meson.build new file mode 100644 index 000000000..27f34075b --- /dev/null +++ b/lib/mesa/src/compiler/glsl/tests/meson.build @@ -0,0 +1,76 @@ +# Copyright © 2017 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 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. + +glsl_blob_test = executable( + 'blob_test', + 'blob_test.c', + c_args : [c_vis_args, c_msvc_compat_args, no_override_init_args], + include_directories : [inc_common, inc_compiler], + link_with : [libglsl], +) + +glsl_cache_test = executable( + 'cache_test', + 'cache_test.c', + c_args : [c_vis_args, c_msvc_compat_args, no_override_init_args], + include_directories : [inc_common, inc_glsl], + link_with : [libglsl], + dependencies : [dep_clock, dep_thread], +) + +glsl_general_ir_test = executable( + 'general_ir_test', + ['array_refcount_test.cpp', 'builtin_variable_test.cpp', + 'invalidate_locations_test.cpp', 'general_ir_test.cpp', + 'lower_int64_test.cpp', 'opt_add_neg_to_sub_test.cpp', 'varyings_test.cpp', + ir_expression_operation_h], + cpp_args : [cpp_vis_args, cpp_msvc_compat_args], + include_directories : [inc_common, inc_glsl], + link_with : [libglsl, libglsl_standalone, libglsl_util], + dependencies : [dep_clock, dep_thread, idep_gtest], +) + +glsl_uniform_initializer_test = executable( + 'uniform_initializer_test', + ['copy_constant_to_storage_tests.cpp', 'set_uniform_initializer_tests.cpp', + 'uniform_initializer_utils.cpp', 'uniform_initializer_utils.h', + ir_expression_operation_h], + cpp_args : [cpp_vis_args, cpp_msvc_compat_args], + include_directories : [inc_common, inc_glsl], + link_with : [libglsl, libglsl_util], + dependencies : [dep_thread, idep_gtest], +) + +glsl_sampler_types_test = executable( + 'sampler_types_test', + ['sampler_types_test.cpp', ir_expression_operation_h], + cpp_args : [cpp_vis_args, cpp_msvc_compat_args], + include_directories : [inc_common, inc_glsl], + link_with : [libglsl, libglsl_util], + dependencies : [dep_thread, idep_gtest], +) + +test('blob_test', glsl_blob_test) +test('cache_test', glsl_cache_test) +test('general_ir_test', glsl_general_ir_test) +test('uniform_initializer_test', glsl_uniform_initializer_test) +test('sampler_types_test', glsl_sampler_types_test) + +# TODO: figure out how to get the shell based tests to work? diff --git a/lib/mesa/src/compiler/nir/nir_linking_helpers.c b/lib/mesa/src/compiler/nir/nir_linking_helpers.c new file mode 100644 index 000000000..54ba1c85e --- /dev/null +++ b/lib/mesa/src/compiler/nir/nir_linking_helpers.c @@ -0,0 +1,152 @@ +/* + * Copyright © 2015 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. + */ + +#include "nir.h" +#include "util/set.h" +#include "util/hash_table.h" + +/* This file contains various little helpers for doing simple linking in + * NIR. Eventually, we'll probably want a full-blown varying packing + * implementation in here. Right now, it just deletes unused things. + */ + +/** + * Returns the bits in the inputs_read, outputs_written, or + * system_values_read bitfield corresponding to this variable. + */ +static uint64_t +get_variable_io_mask(nir_variable *var, gl_shader_stage stage) +{ + /* TODO: add support for tess patches */ + if (var->data.patch || var->data.location < 0) + return 0; + + assert(var->data.mode == nir_var_shader_in || + var->data.mode == nir_var_shader_out || + var->data.mode == nir_var_system_value); + assert(var->data.location >= 0); + + const struct glsl_type *type = var->type; + if (nir_is_per_vertex_io(var, stage)) { + assert(glsl_type_is_array(type)); + type = glsl_get_array_element(type); + } + + unsigned slots = glsl_count_attribute_slots(type, false); + return ((1ull << slots) - 1) << var->data.location; +} + +static void +tcs_add_output_reads(nir_shader *shader, uint64_t *read) +{ + nir_foreach_function(function, shader) { + if (function->impl) { + nir_foreach_block(block, function->impl) { + nir_foreach_instr(instr, block) { + if (instr->type != nir_instr_type_intrinsic) + continue; + + nir_intrinsic_instr *intrin_instr = + nir_instr_as_intrinsic(instr); + if (intrin_instr->intrinsic == nir_intrinsic_load_var && + intrin_instr->variables[0]->var->data.mode == + nir_var_shader_out) { + + nir_variable *var = intrin_instr->variables[0]->var; + read[var->data.location_frac] |= + get_variable_io_mask(intrin_instr->variables[0]->var, + shader->info.stage); + } + } + } + } + } +} + +static bool +remove_unused_io_vars(nir_shader *shader, struct exec_list *var_list, + uint64_t *used_by_other_stage) +{ + bool progress = false; + + nir_foreach_variable_safe(var, var_list) { + /* TODO: add patch support */ + if (var->data.patch) + continue; + + if (var->data.location < VARYING_SLOT_VAR0 && var->data.location >= 0) + continue; + + if (var->data.always_active_io) + continue; + + uint64_t other_stage = used_by_other_stage[var->data.location_frac]; + + if (!(other_stage & get_variable_io_mask(var, shader->info.stage))) { + /* This one is invalid, make it a global variable instead */ + var->data.location = 0; + var->data.mode = nir_var_global; + + exec_node_remove(&var->node); + exec_list_push_tail(&shader->globals, &var->node); + + progress = true; + } + } + + return progress; +} + +bool +nir_remove_unused_varyings(nir_shader *producer, nir_shader *consumer) +{ + assert(producer->info.stage != MESA_SHADER_FRAGMENT); + assert(consumer->info.stage != MESA_SHADER_VERTEX); + + uint64_t read[4] = { 0 }, written[4] = { 0 }; + + nir_foreach_variable(var, &producer->outputs) { + written[var->data.location_frac] |= + get_variable_io_mask(var, producer->info.stage); + } + + nir_foreach_variable(var, &consumer->inputs) { + read[var->data.location_frac] |= + get_variable_io_mask(var, consumer->info.stage); + } + + /* Each TCS invocation can read data written by other TCS invocations, + * so even if the outputs are not used by the TES we must also make + * sure they are not read by the TCS before demoting them to globals. + */ + if (producer->info.stage == MESA_SHADER_TESS_CTRL) + tcs_add_output_reads(producer, read); + + bool progress = false; + progress = remove_unused_io_vars(producer, &producer->outputs, read); + + progress = + remove_unused_io_vars(consumer, &consumer->inputs, written) || progress; + + return progress; +} diff --git a/lib/mesa/src/compiler/nir/nir_lower_alpha_test.c b/lib/mesa/src/compiler/nir/nir_lower_alpha_test.c new file mode 100644 index 000000000..6bf9ff142 --- /dev/null +++ b/lib/mesa/src/compiler/nir/nir_lower_alpha_test.c @@ -0,0 +1,111 @@ +/* + * Copyright © 2017 Broadcom + * + * 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 + * + * Implements GL alpha testing by comparing the output color's alpha to the + * alpha_ref intrinsic and emitting a discard based on it. + * + * The alpha_to_one value overrides the source alpha to 1.0 to implement + * GL_SAMPLE_ALPHA_TO_ONE, which applies before the alpha test (and would be + * rather silly to use with alpha test, but the spec permits). + */ + +#include "nir/nir.h" +#include "nir/nir_builder.h" + +void +nir_lower_alpha_test(nir_shader *shader, enum compare_func func, + bool alpha_to_one) +{ + assert(shader->info.stage == MESA_SHADER_FRAGMENT); + + nir_foreach_function(function, shader) { + nir_function_impl *impl = function->impl; + nir_builder b; + nir_builder_init(&b, impl); + b.cursor = nir_before_cf_list(&impl->body); + + nir_foreach_block(block, impl) { + nir_foreach_instr_safe(instr, block) { + if (instr->type == nir_instr_type_intrinsic) { + nir_intrinsic_instr *intr = nir_instr_as_intrinsic(instr); + + nir_variable *out = NULL; + + switch (intr->intrinsic) { + case nir_intrinsic_store_var: + out = intr->variables[0]->var; + break; + case nir_intrinsic_store_output: + /* already had i/o lowered.. lookup the matching output var: */ + nir_foreach_variable(var, &shader->outputs) { + int drvloc = var->data.driver_location; + if (nir_intrinsic_base(intr) == drvloc) { + out = var; + break; + } + } + assume(out); + break; + default: + continue; + } + + if (out->data.mode != nir_var_shader_out) + continue; + + if (out->data.location != FRAG_RESULT_COLOR && + out->data.location != FRAG_RESULT_DATA0) + continue; + + b.cursor = nir_before_instr(&intr->instr); + + nir_ssa_def *alpha; + if (alpha_to_one) { + alpha = nir_imm_float(&b, 1.0); + } else { + alpha = nir_channel(&b, nir_ssa_for_src(&b, intr->src[0], 4), + 3); + } + + nir_ssa_def *condition = + nir_compare_func(&b, func, + alpha, nir_load_alpha_ref_float(&b)); + + nir_intrinsic_instr *discard = + nir_intrinsic_instr_create(b.shader, + nir_intrinsic_discard_if); + discard->num_components = 1; + discard->src[0] = nir_src_for_ssa(nir_inot(&b, condition)); + nir_builder_instr_insert(&b, &discard->instr); + shader->info.fs.uses_discard = true; + } + } + } + + nir_metadata_preserve(impl, nir_metadata_block_index | + nir_metadata_dominance); + } +} diff --git a/lib/mesa/src/compiler/nir/nir_lower_samplers_as_deref.c b/lib/mesa/src/compiler/nir/nir_lower_samplers_as_deref.c new file mode 100644 index 000000000..bdbd8672f --- /dev/null +++ b/lib/mesa/src/compiler/nir/nir_lower_samplers_as_deref.c @@ -0,0 +1,243 @@ +/* + * Copyright (C) 2005-2007 Brian Paul All Rights Reserved. + * Copyright (C) 2008 VMware, Inc. All Rights Reserved. + * Copyright © 2014 Intel Corporation + * Copyright © 2017 Advanced Micro Devices, Inc. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice (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 + * + * Lower sampler and image references of (non-bindless) uniforms by removing + * struct dereferences, and synthesizing new uniform variables without structs + * if required. + * + * This will allow backends to have a simple, uniform treatment of bindless and + * non-bindless samplers and images. + * + * Example: + * + * struct S { + * sampler2D tex[2]; + * sampler2D other; + * }; + * uniform S s[2]; + * + * tmp = texture(s[n].tex[m], coord); + * + * Becomes: + * + * decl_var uniform INTERP_MODE_NONE sampler2D[2][2] lower@s.tex (...) + * + * vec1 32 ssa_idx = $(2 * n + m) + * vec4 32 ssa_out = tex ssa_coord (coord), lower@s.tex[n][m] (texture), lower@s.tex[n][m] (sampler) + * + * and lower@s.tex has var->data.binding set to the base index as defined by + * the opaque uniform mapping. + */ + +#include "nir.h" +#include "nir_builder.h" +#include "compiler/glsl/ir_uniform.h" + +#include "main/compiler.h" +#include "main/mtypes.h" +#include "program/prog_parameter.h" +#include "program/program.h" + +struct lower_samplers_as_deref_state { + nir_shader *shader; + const struct gl_shader_program *shader_program; + struct hash_table *remap_table; +}; + +static void +remove_struct_derefs(nir_deref *tail, + struct lower_samplers_as_deref_state *state, + nir_builder *b, char **path, unsigned *location) +{ + if (!tail->child) + return; + + switch (tail->child->deref_type) { + case nir_deref_type_array: { + unsigned length = glsl_get_length(tail->type); + + remove_struct_derefs(tail->child, state, b, path, location); + + tail->type = glsl_get_array_instance(tail->child->type, length); + break; + } + + case nir_deref_type_struct: { + nir_deref_struct *deref_struct = nir_deref_as_struct(tail->child); + + *location += glsl_get_record_location_offset(tail->type, deref_struct->index); + ralloc_asprintf_append(path, ".%s", + glsl_get_struct_elem_name(tail->type, deref_struct->index)); + + remove_struct_derefs(tail->child, state, b, path, location); + + /* Drop the struct deref and re-parent. */ + ralloc_steal(tail, tail->child->child); + tail->type = tail->child->type; + tail->child = tail->child->child; + break; + } + + default: + unreachable("Invalid deref type"); + break; + } +} + +static void +lower_deref(nir_deref_var *deref, + struct lower_samplers_as_deref_state *state, + nir_builder *b) +{ + nir_variable *var = deref->var; + gl_shader_stage stage = state->shader->info.stage; + unsigned location = var->data.location; + unsigned binding; + const struct glsl_type *orig_type = deref->deref.type; + char *path; + + assert(var->data.mode == nir_var_uniform); + + path = ralloc_asprintf(state->remap_table, "lower@%s", var->name); + remove_struct_derefs(&deref->deref, state, b, &path, &location); + + assert(location < state->shader_program->data->NumUniformStorage && + state->shader_program->data->UniformStorage[location].opaque[stage].active); + + binding = state->shader_program->data->UniformStorage[location].opaque[stage].index; + + if (orig_type == deref->deref.type) { + /* Fast path: We did not encounter any struct derefs. */ + var->data.binding = binding; + return; + } + + uint32_t hash = _mesa_key_hash_string(path); + struct hash_entry *h = + _mesa_hash_table_search_pre_hashed(state->remap_table, hash, path); + + if (h) { + var = (nir_variable *)h->data; + } else { + var = nir_variable_create(state->shader, nir_var_uniform, deref->deref.type, path); + var->data.binding = binding; + _mesa_hash_table_insert_pre_hashed(state->remap_table, hash, path, var); + } + + deref->var = var; +} + +static bool +lower_sampler(nir_tex_instr *instr, struct lower_samplers_as_deref_state *state, + nir_builder *b) +{ + /* In GLSL, we only fill out the texture field. The sampler is inferred */ + assert(instr->texture != NULL); + assert(instr->sampler == NULL); + + b->cursor = nir_before_instr(&instr->instr); + lower_deref(instr->texture, state, b); + + if (instr->op != nir_texop_txf_ms && + instr->op != nir_texop_txf_ms_mcs && + instr->op != nir_texop_samples_identical) { + nir_instr_rewrite_deref(&instr->instr, &instr->sampler, + nir_deref_var_clone(instr->texture, instr)); + } else { + assert(!instr->sampler); + } + + return true; +} + +static bool +lower_intrinsic(nir_intrinsic_instr *instr, + struct lower_samplers_as_deref_state *state, + nir_builder *b) +{ + if (instr->intrinsic == nir_intrinsic_image_load || + instr->intrinsic == nir_intrinsic_image_store || + instr->intrinsic == nir_intrinsic_image_atomic_add || + instr->intrinsic == nir_intrinsic_image_atomic_min || + instr->intrinsic == nir_intrinsic_image_atomic_max || + instr->intrinsic == nir_intrinsic_image_atomic_and || + instr->intrinsic == nir_intrinsic_image_atomic_or || + instr->intrinsic == nir_intrinsic_image_atomic_xor || + instr->intrinsic == nir_intrinsic_image_atomic_exchange || + instr->intrinsic == nir_intrinsic_image_atomic_comp_swap || + instr->intrinsic == nir_intrinsic_image_size) { + b->cursor = nir_before_instr(&instr->instr); + lower_deref(instr->variables[0], state, b); + return true; + } + + return false; +} + +static bool +lower_impl(nir_function_impl *impl, struct lower_samplers_as_deref_state *state) +{ + nir_builder b; + nir_builder_init(&b, impl); + bool progress = false; + + nir_foreach_block(block, impl) { + nir_foreach_instr(instr, block) { + if (instr->type == nir_instr_type_tex) + progress |= lower_sampler(nir_instr_as_tex(instr), state, &b); + else if (instr->type == nir_instr_type_intrinsic) + progress |= lower_intrinsic(nir_instr_as_intrinsic(instr), state, &b); + } + } + + return progress; +} + +bool +nir_lower_samplers_as_deref(nir_shader *shader, + const struct gl_shader_program *shader_program) +{ + bool progress = false; + struct lower_samplers_as_deref_state state; + + state.shader = shader; + state.shader_program = shader_program; + state.remap_table = _mesa_hash_table_create(NULL, _mesa_key_hash_string, + _mesa_key_string_equal); + + nir_foreach_function(function, shader) { + if (function->impl) + progress |= lower_impl(function->impl, &state); + } + + /* keys are freed automatically by ralloc */ + _mesa_hash_table_destroy(state.remap_table, NULL); + + return progress; +} diff --git a/lib/mesa/src/compiler/nir/nir_lower_uniforms_to_ubo.c b/lib/mesa/src/compiler/nir/nir_lower_uniforms_to_ubo.c new file mode 100644 index 000000000..15bf0d985 --- /dev/null +++ b/lib/mesa/src/compiler/nir/nir_lower_uniforms_to_ubo.c @@ -0,0 +1,97 @@ +/* + * Copyright 2017 Advanced Micro Devices, Inc. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * on the rights to use, copy, modify, merge, publish, distribute, sub + * license, and/or sell copies of the Software, and to permit persons to whom + * the Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice (including the next + * paragraph) shall be included in all copies or substantial portions of the + * Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL + * THE AUTHOR(S) AND/OR THEIR SUPPLIERS BE LIABLE FOR ANY CLAIM, + * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR + * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE + * USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +/* + * Remap load_uniform intrinsics to UBO accesses of UBO binding point 0. Both + * the base and the offset are interpreted as 16-byte units. + * + * Simultaneously, remap existing UBO accesses by increasing their binding + * point by 1. + */ + +#include "nir.h" +#include "nir_builder.h" + +static bool +lower_instr(nir_intrinsic_instr *instr, nir_builder *b) +{ + b->cursor = nir_before_instr(&instr->instr); + + if (instr->intrinsic == nir_intrinsic_load_ubo) { + nir_ssa_def *old_idx = nir_ssa_for_src(b, instr->src[0], 1); + nir_ssa_def *new_idx = nir_iadd(b, old_idx, nir_imm_int(b, 1)); + nir_instr_rewrite_src(&instr->instr, &instr->src[0], + nir_src_for_ssa(new_idx)); + return true; + } + + if (instr->intrinsic == nir_intrinsic_load_uniform) { + nir_ssa_def *ubo_idx = nir_imm_int(b, 0); + nir_ssa_def *ubo_offset = + nir_imul(b, nir_imm_int(b, 16), + nir_iadd(b, nir_imm_int(b, nir_intrinsic_base(instr)), + nir_ssa_for_src(b, instr->src[0], 1))); + + nir_intrinsic_instr *load = + nir_intrinsic_instr_create(b->shader, nir_intrinsic_load_ubo); + load->num_components = instr->num_components; + load->src[0] = nir_src_for_ssa(ubo_idx); + load->src[1] = nir_src_for_ssa(ubo_offset); + nir_ssa_dest_init(&load->instr, &load->dest, + load->num_components, instr->dest.ssa.bit_size, + instr->dest.ssa.name); + nir_builder_instr_insert(b, &load->instr); + nir_ssa_def_rewrite_uses(&instr->dest.ssa, nir_src_for_ssa(&load->dest.ssa)); + + nir_instr_remove(&instr->instr); + return true; + } + + return false; +} + +bool +nir_lower_uniforms_to_ubo(nir_shader *shader) +{ + bool progress = false; + + nir_foreach_function(function, shader) { + if (function->impl) { + nir_builder builder; + nir_builder_init(&builder, function->impl); + nir_foreach_block(block, function->impl) { + nir_foreach_instr_safe(instr, block) { + if (instr->type == nir_instr_type_intrinsic) + progress |= lower_instr(nir_instr_as_intrinsic(instr), + &builder); + } + } + + nir_metadata_preserve(function->impl, nir_metadata_block_index | + nir_metadata_dominance); + } + } + + return progress; +} + diff --git a/lib/mesa/src/compiler/nir/nir_lower_vec_to_movs.c b/lib/mesa/src/compiler/nir/nir_lower_vec_to_movs.c index 711ddd38b..8b24376b0 100644 --- a/lib/mesa/src/compiler/nir/nir_lower_vec_to_movs.c +++ b/lib/mesa/src/compiler/nir/nir_lower_vec_to_movs.c @@ -230,6 +230,7 @@ lower_vec_to_movs_block(nir_block *block, nir_function_impl *impl) continue; /* The loop */ } + bool vec_had_ssa_dest = vec->dest.dest.is_ssa; if (vec->dest.dest.is_ssa) { /* Since we insert multiple MOVs, we have a register destination. */ nir_register *reg = nir_local_reg_create(impl); @@ -263,7 +264,11 @@ lower_vec_to_movs_block(nir_block *block, nir_function_impl *impl) if (!(vec->dest.write_mask & (1 << i))) continue; - if (!(finished_write_mask & (1 << i))) + /* Coalescing moves the register writes from the vec up to the ALU + * instruction in the source. We can only do this if the original + * vecN had an SSA destination. + */ + if (vec_had_ssa_dest && !(finished_write_mask & (1 << i))) finished_write_mask |= try_coalesce(vec, i); if (!(finished_write_mask & (1 << i))) diff --git a/lib/mesa/src/mapi/glapi/gen/ARB_clear_buffer_object.xml b/lib/mesa/src/mapi/glapi/gen/ARB_clear_buffer_object.xml index 2284eacd6..25a42b3a4 100644 --- a/lib/mesa/src/mapi/glapi/gen/ARB_clear_buffer_object.xml +++ b/lib/mesa/src/mapi/glapi/gen/ARB_clear_buffer_object.xml @@ -8,7 +8,7 @@ <category name="GL_ARB_clear_buffer_object" number="121"> - <function name ="ClearBufferData"> + <function name ="ClearBufferData" no_error="true"> <param name="target" type="GLenum"/> <param name="internalformat" type="GLenum"/> <param name="format" type="GLenum"/> @@ -16,7 +16,7 @@ <param name="data" type="const GLvoid *"/> </function> - <function name ="ClearBufferSubData"> + <function name ="ClearBufferSubData" no_error="true"> <param name="target" type="GLenum"/> <param name="internalformat" type="GLenum"/> <param name="offset" type="GLintptr"/> diff --git a/lib/mesa/src/mapi/glapi/gen/ARB_get_program_binary.xml b/lib/mesa/src/mapi/glapi/gen/ARB_get_program_binary.xml index 25e0a37c8..c521c04de 100644 --- a/lib/mesa/src/mapi/glapi/gen/ARB_get_program_binary.xml +++ b/lib/mesa/src/mapi/glapi/gen/ARB_get_program_binary.xml @@ -26,7 +26,7 @@ <param name="length" type="GLsizei"/> </function> - <function name="ProgramParameteri" es2="3.0"> + <function name="ProgramParameteri" es2="3.0" no_error="true"> <param name="program" type="GLuint"/> <param name="pname" type="GLenum"/> <param name="value" type="GLint"/> diff --git a/lib/mesa/src/mapi/glapi/gen/ARB_robustness.xml b/lib/mesa/src/mapi/glapi/gen/ARB_robustness.xml index 9b2f2f0a7..1f6ac4696 100644 --- a/lib/mesa/src/mapi/glapi/gen/ARB_robustness.xml +++ b/lib/mesa/src/mapi/glapi/gen/ARB_robustness.xml @@ -82,7 +82,7 @@ <param name="img" type="GLvoid *" output="true"/> </function> - <function name="ReadnPixelsARB"> + <function name="ReadnPixelsARB" no_error="true"> <param name="x" type="GLint"/> <param name="y" type="GLint"/> <param name="width" type="GLsizei"/> diff --git a/lib/mesa/src/mapi/glapi/gen/ARB_tessellation_shader.xml b/lib/mesa/src/mapi/glapi/gen/ARB_tessellation_shader.xml index e26f227b6..d0b03750e 100644 --- a/lib/mesa/src/mapi/glapi/gen/ARB_tessellation_shader.xml +++ b/lib/mesa/src/mapi/glapi/gen/ARB_tessellation_shader.xml @@ -50,7 +50,7 @@ <enum value="0x8E8A" name="MAX_TESS_EVALUATION_UNIFORM_BLOCKS"/> <enum value="0x8221" name="PRIMITIVE_RESTART_FOR_PATCHES_SUPPORTED"/> - <function name="PatchParameteri" es2="3.2"> + <function name="PatchParameteri" es2="3.2" no_error="true"> <param name="pname" type="GLenum"/> <param name="value" type="GLint"/> </function> diff --git a/lib/mesa/src/mapi/glapi/gen/ARB_texture_multisample.xml b/lib/mesa/src/mapi/glapi/gen/ARB_texture_multisample.xml index 595e1c7ea..0040c5398 100644 --- a/lib/mesa/src/mapi/glapi/gen/ARB_texture_multisample.xml +++ b/lib/mesa/src/mapi/glapi/gen/ARB_texture_multisample.xml @@ -59,7 +59,7 @@ <param name="val" type="GLfloat *"/> </function> - <function name="SampleMaski" es2="3.1"> + <function name="SampleMaski" es2="3.1" no_error="true"> <param name="index" type="GLuint"/> <param name="mask" type="GLbitfield"/> </function> diff --git a/lib/mesa/src/mapi/glapi/gen/ARB_texture_storage.xml b/lib/mesa/src/mapi/glapi/gen/ARB_texture_storage.xml index 7df394241..4dbab3947 100644 --- a/lib/mesa/src/mapi/glapi/gen/ARB_texture_storage.xml +++ b/lib/mesa/src/mapi/glapi/gen/ARB_texture_storage.xml @@ -10,14 +10,14 @@ <enum name="TEXTURE_IMMUTABLE_FORMAT" value="0x912F"/> - <function name="TexStorage1D"> + <function name="TexStorage1D" no_error="true"> <param name="target" type="GLenum"/> <param name="levels" type="GLsizei"/> <param name="internalFormat" type="GLenum"/> <param name="width" type="GLsizei"/> </function> - <function name="TexStorage2D" es2="3.0"> + <function name="TexStorage2D" es2="3.0" no_error="true"> <param name="target" type="GLenum"/> <param name="levels" type="GLsizei"/> <param name="internalFormat" type="GLenum"/> @@ -25,7 +25,7 @@ <param name="height" type="GLsizei"/> </function> - <function name="TexStorage3D" es2="3.0"> + <function name="TexStorage3D" es2="3.0" no_error="true"> <param name="target" type="GLenum"/> <param name="levels" type="GLsizei"/> <param name="internalFormat" type="GLenum"/> diff --git a/lib/mesa/src/mapi/glapi/gen/ARB_texture_view.xml b/lib/mesa/src/mapi/glapi/gen/ARB_texture_view.xml index 4215fc5bd..0c20ef97d 100644 --- a/lib/mesa/src/mapi/glapi/gen/ARB_texture_view.xml +++ b/lib/mesa/src/mapi/glapi/gen/ARB_texture_view.xml @@ -7,7 +7,7 @@ <category name="GL_ARB_texture_view" number="124"> - <function name="TextureView"> + <function name="TextureView" no_error="true"> <param name="texture" type="GLuint"/> <param name="target" type="GLenum"/> <param name="origtexture" type="GLuint"/> diff --git a/lib/mesa/src/mapi/glapi/gen/EXT_external_objects.xml b/lib/mesa/src/mapi/glapi/gen/EXT_external_objects.xml new file mode 100644 index 000000000..25e6879ec --- /dev/null +++ b/lib/mesa/src/mapi/glapi/gen/EXT_external_objects.xml @@ -0,0 +1,234 @@ +<?xml version="1.0"?> +<!DOCTYPE OpenGLAPI SYSTEM "gl_API.dtd"> + +<!-- Note: no GLX protocol info yet. --> + + +<OpenGLAPI> + +<category name="EXT_external_objects" number="503"> + + <enum name="TEXTURE_TILING_EXT" value="0x9580"/> + <enum name="DEDICATED_MEMORY_OBJECT_EXT" value="0x9581"/> + <enum name="PROTECTED_MEMORY_OBJECT_EXT" value="0x959B"/> + <enum name="NUM_TILING_TYPES_EXT" value="0x9582"/> + <enum name="TILING_TYPES_EXT" value="0x9583"/> + <enum name="OPTIMAL_TILING_EXT" value="0x9584"/> + <enum name="LINEAR_TILING_EXT" value="0x9585"/> + <enum name="NUM_DEVICE_UUIDS_EXT" value="0x9596"/> + <enum name="DEVICE_UUID_EXT" value="0x9597"/> + <enum name="DRIVER_UUID_EXT" value="0x9598"/> + <enum name="LAYOUT_GENERAL_EXT" value="0x958D"/> + <enum name="LAYOUT_COLOR_ATTACHMENT_EXT" value="0x958E"/> + <enum name="LAYOUT_DEPTH_STENCIL_ATTACHMENT_EXT" value="0x958F"/> + <enum name="LAYOUT_DEPTH_STENCIL_READ_ONLY_EXT" value="0x9590"/> + <enum name="LAYOUT_SHADER_READ_ONLY_EXT" value="0x9591"/> + <enum name="LAYOUT_TRANSFER_SRC_EXT" value="0x9592"/> + <enum name="LAYOUT_TRANSFER_DST_EXT" value="0x9593"/> + + <function name="GetUnsignedBytevEXT" es2="3.2"> + <param name="pname" type="GLenum"/> + <param name="data" type="GLubyte *"/> + </function> + + <function name="GetUnsignedBytei_vEXT" es2="3.2"> + <param name="target" type="GLenum"/> + <param name="index" type="GLuint"/> + <param name="data" type="GLubyte *"/> + </function> + + <function name="DeleteMemoryObjectsEXT" es2="3.2"> + <param name="n" type="GLsizei"/> + <param name="memoryObjects" type="const GLuint *"/> + </function> + + <function name="IsMemoryObjectEXT" es2="3.2"> + <param name="memoryObject" type="GLuint"/> + <return type="GLboolean"/> + </function> + + <function name="CreateMemoryObjectsEXT" es2="3.2"> + <param name="n" type="GLsizei"/> + <param name="memoryObjects" type="GLuint *"/> + </function> + + <function name="MemoryObjectParameterivEXT" es2="3.2"> + <param name="memoryObject" type="GLuint"/> + <param name="pname" type="GLenum"/> + <param name="params" type="const GLint *"/> + </function> + + <function name="GetMemoryObjectParameterivEXT" es2="3.2"> + <param name="memoryObject" type="GLuint"/> + <param name="pname" type="GLenum"/> + <param name="params" type="GLint *"/> + </function> + + <function name="TexStorageMem2DEXT" es2="3.2"> + <param name="target" type="GLenum"/> + <param name="levels" type="GLsizei"/> + <param name="internalFormat" type="GLenum"/> + <param name="width" type="GLsizei"/> + <param name="height" type="GLsizei"/> + <param name="memory" type="GLuint"/> + <param name="offset" type="GLuint64"/> + </function> + + <function name="TexStorageMem2DMultisampleEXT" es2="3.2"> + <param name="target" type="GLenum"/> + <param name="samples" type="GLsizei"/> + <param name="internalFormat" type="GLenum"/> + <param name="width" type="GLsizei"/> + <param name="height" type="GLsizei"/> + <param name="fixedSampleLocations" type="GLboolean"/> + <param name="memory" type="GLuint"/> + <param name="offset" type="GLuint64"/> + </function> + + <function name="TexStorageMem3DEXT" es2="3.2"> + <param name="target" type="GLenum"/> + <param name="levels" type="GLsizei"/> + <param name="internalFormat" type="GLenum"/> + <param name="width" type="GLsizei"/> + <param name="height" type="GLsizei"/> + <param name="depth" type="GLsizei"/> + <param name="memory" type="GLuint"/> + <param name="offset" type="GLuint64"/> + </function> + + <function name="TexStorageMem3DMultisampleEXT" es2="3.2"> + <param name="target" type="GLenum"/> + <param name="samples" type="GLsizei"/> + <param name="internalFormat" type="GLenum"/> + <param name="width" type="GLsizei"/> + <param name="height" type="GLsizei"/> + <param name="depth" type="GLsizei"/> + <param name="fixedSampleLocations" type="GLboolean"/> + <param name="memory" type="GLuint"/> + <param name="offset" type="GLuint64"/> + </function> + + <function name="BufferStorageMemEXT" es2="3.2" no_error="true"> + <param name="target" type="GLenum"/> + <param name="size" type="GLsizeiptr"/> + <param name="memory" type="GLuint"/> + <param name="offset" type="GLuint64"/> + </function> + + <function name="TextureStorageMem2DEXT" es2="3.2"> + <param name="texture" type="GLenum"/> + <param name="levels" type="GLsizei"/> + <param name="internalFormat" type="GLenum"/> + <param name="width" type="GLsizei"/> + <param name="height" type="GLsizei"/> + <param name="memory" type="GLuint"/> + <param name="offset" type="GLuint64"/> + </function> + + <function name="TextureStorageMem2DMultisampleEXT" es2="3.2"> + <param name="texture" type="GLuint"/> + <param name="samples" type="GLsizei"/> + <param name="internalFormat" type="GLenum"/> + <param name="width" type="GLsizei"/> + <param name="height" type="GLsizei"/> + <param name="fixedSampleLocations" type="GLboolean"/> + <param name="memory" type="GLuint"/> + <param name="offset" type="GLuint64"/> + </function> + + <function name="TextureStorageMem3DEXT" es2="3.2"> + <param name="texture" type="GLuint"/> + <param name="levels" type="GLsizei"/> + <param name="internalFormat" type="GLenum"/> + <param name="width" type="GLsizei"/> + <param name="height" type="GLsizei"/> + <param name="depth" type="GLsizei"/> + <param name="memory" type="GLuint"/> + <param name="offset" type="GLuint64"/> + </function> + + <function name="TextureStorageMem3DMultisampleEXT" es2="3.2"> + <param name="texture" type="GLuint"/> + <param name="samples" type="GLsizei"/> + <param name="internalFormat" type="GLenum"/> + <param name="width" type="GLsizei"/> + <param name="height" type="GLsizei"/> + <param name="depth" type="GLsizei"/> + <param name="fixedSampleLocations" type="GLboolean"/> + <param name="memory" type="GLuint"/> + <param name="offset" type="GLuint64"/> + </function> + + <function name="NamedBufferStorageMemEXT" es2="3.2" no_error="true"> + <param name="buffer" type="GLuint"/> + <param name="size" type="GLsizeiptr"/> + <param name="memory" type="GLuint"/> + <param name="offset" type="GLuint64"/> + </function> + + <function name="TexStorageMem1DEXT"> + <param name="target" type="GLenum"/> + <param name="levels" type="GLsizei"/> + <param name="internalFormat" type="GLenum"/> + <param name="width" type="GLsizei"/> + <param name="memory" type="GLuint"/> + <param name="offset" type="GLuint64"/> + </function> + + <function name="TextureStorageMem1DEXT"> + <param name="texture" type="GLuint"/> + <param name="levels" type="GLsizei"/> + <param name="internalFormat" type="GLenum"/> + <param name="width" type="GLsizei"/> + <param name="memory" type="GLuint"/> + <param name="offset" type="GLuint64"/> + </function> + + <function name="GenSemaphoresEXT" es2="3.2"> + <param name="n" type="GLsizei"/> + <param name="semaphores" type="GLuint *"/> + </function> + + <function name="DeleteSemaphoresEXT" es2="3.2"> + <param name="n" type="GLsizei"/> + <param name="semaphores" type="const GLuint *"/> + </function> + + <function name="IsSemaphoreEXT" es2="3.2"> + <param name="semaphore" type="GLuint"/> + <return type="GLboolean"/> + </function> + + <function name="SemaphoreParameterui64vEXT" es2="3.2"> + <param name="semaphore" type="GLuint"/> + <param name="pname" type="GLenum"/> + <param name="params" type="const GLuint64 *"/> + </function> + + <function name="GetSemaphoreParameterui64vEXT" es2="3.2"> + <param name="semaphore" type="GLuint"/> + <param name="pname" type="GLenum"/> + <param name="params" type="GLuint64 *"/> + </function> + + <function name="WaitSemaphoreEXT" es2="3.2"> + <param name="semaphore" type="GLuint"/> + <param name="numBufferBarriers" type="GLuint"/> + <param name="buffers" type="const GLuint *"/> + <param name="numTextureBarriers" type="GLuint"/> + <param name="textures" type="const GLuint *"/> + <param name="srcLayouts" type="const GLenum *"/> + </function> + + <function name="SignalSemaphoreEXT" es2="3.2"> + <param name="semaphore" type="GLuint"/> + <param name="numBufferBarriers" type="GLuint"/> + <param name="buffers" type="const GLuint *"/> + <param name="numTextureBarriers" type="GLuint"/> + <param name="textures" type="const GLuint *"/> + <param name="dstLayouts" type="const GLenum *"/> + </function> + +</category> + +</OpenGLAPI> diff --git a/lib/mesa/src/mapi/glapi/gen/EXT_external_objects_fd.xml b/lib/mesa/src/mapi/glapi/gen/EXT_external_objects_fd.xml new file mode 100644 index 000000000..6eaa3f5b0 --- /dev/null +++ b/lib/mesa/src/mapi/glapi/gen/EXT_external_objects_fd.xml @@ -0,0 +1,28 @@ +<?xml version="1.0"?> +<!DOCTYPE OpenGLAPI SYSTEM "gl_API.dtd"> + +<!-- Note: no GLX protocol info yet. --> + + +<OpenGLAPI> + +<category name="EXT_external_objects_fd" number="504"> + + <enum name="HANDLE_TYPE_OPAQUE_FD_EXT" value="0x9586"/> + + <function name="ImportMemoryFdEXT" es2="3.2"> + <param name="memory" type="GLuint"/> + <param name="size" type="GLuint64"/> + <param name="handleType" type="GLenum"/> + <param name="fd" type="GLint"/> + </function> + + <function name="ImportSemaphoreFdEXT" es2="3.2"> + <param name="semaphore" type="GLuint"/> + <param name="handleType" type="GLenum"/> + <param name="fd" type="GLint"/> + </function> + +</category> + +</OpenGLAPI> diff --git a/lib/mesa/src/mapi/glapi/gen/GL4x.xml b/lib/mesa/src/mapi/glapi/gen/GL4x.xml index 53b77896c..512addc2b 100644 --- a/lib/mesa/src/mapi/glapi/gen/GL4x.xml +++ b/lib/mesa/src/mapi/glapi/gen/GL4x.xml @@ -9,7 +9,7 @@ <enum name="SAMPLE_SHADING" value="0x8C36"/> <enum name="MIN_SAMPLE_SHADING_VALUE" value="0x8C37"/> - <function name="MinSampleShading" es2="3.2"> + <function name="MinSampleShading" es2="3.2" no_error="true"> <param name="value" type="GLfloat"/> </function> @@ -42,6 +42,7 @@ <category name="4.3"> <enum name="SHADER_STORAGE_BARRIER_BIT" value="0x2000" /> + <enum name="NUM_SHADING_LANGUAGE_VERSIONS" value="0x82E9" /> <enum name="MAX_COMBINED_SHADER_OUTPUT_RESOURCES" value="0x8F39" /> <enum name="SHADER_STORAGE_BUFFER" value="0x90D2"/> <enum name="SHADER_STORAGE_BUFFER_BINDING" value="0x90D3"/> @@ -61,9 +62,18 @@ </category> <category name="4.5"> - <function name="MemoryBarrierByRegion" es2="3.1"> + <function name="MemoryBarrierByRegion" es2="3.1" no_error="true"> <param name="barriers" type="GLbitfield"/> </function> </category> +<category name="4.6"> + <function name="PolygonOffsetClamp" alias="PolygonOffsetClampEXT"> + <param name="factor" type="GLfloat"/> + <param name="units" type="GLfloat"/> + <param name="clamp" type="GLfloat"/> + </function> + <enum name="POLYGON_OFFSET_CLAMP" value="0x8E1B"/> +</category> + </OpenGLAPI> diff --git a/lib/mesa/src/mapi/glapi/gen/MESA_tile_raster_order.xml b/lib/mesa/src/mapi/glapi/gen/MESA_tile_raster_order.xml new file mode 100644 index 000000000..7cc73ca4b --- /dev/null +++ b/lib/mesa/src/mapi/glapi/gen/MESA_tile_raster_order.xml @@ -0,0 +1,12 @@ +<?xml version="1.0"?> +<!DOCTYPE OpenGLAPI SYSTEM "gl_API.dtd"> + +<OpenGLAPI> + +<category name="GL_MESA_tile_rasterizer_order" number="515"> + <enum name="TILE_RASTER_ORDER_FIXED_MESA" value="0x8BB8"/> + <enum name="TILE_RASTER_ORDER_INCREASING_X_MESA" value="0x8BB9"/> + <enum name="TILE_RASTER_ORDER_INCREASING_Y_MESA" value="0x8BBA"/> +</category> + +</OpenGLAPI> diff --git a/lib/mesa/src/mapi/glapi/glapi.h b/lib/mesa/src/mapi/glapi/glapi.h index f1ad4c1b5..d5d4e0a03 100644 --- a/lib/mesa/src/mapi/glapi/glapi.h +++ b/lib/mesa/src/mapi/glapi/glapi.h @@ -161,6 +161,9 @@ _glapi_get_proc_name(unsigned int offset); #if defined(GLX_USE_APPLEGL) || defined(GLX_USE_WINDOWSGL) _GLAPI_EXPORT struct _glapi_table * _glapi_create_table_from_handle(void *handle, const char *symbol_prefix); + +_GLAPI_EXPORT void +_glapi_table_patch(struct _glapi_table *, const char *name, void *wrapper); #endif diff --git a/lib/mesa/src/mapi/glapi/tests/check_table.cpp b/lib/mesa/src/mapi/glapi/tests/check_table.cpp index 09bf4f358..f23f00be5 100644 --- a/lib/mesa/src/mapi/glapi/tests/check_table.cpp +++ b/lib/mesa/src/mapi/glapi/tests/check_table.cpp @@ -24,10 +24,8 @@ #include <gtest/gtest.h> #include "../mesa/main/glheader.h" -extern "C" { #include "glapi/glapi.h" #include "glapi/glapitable.h" -} struct name_offset { const char *name; @@ -1404,9 +1402,7 @@ const struct name_offset known_dispatch[] = { { "glPointParameteri", _O(PointParameteri) }, { "glPointParameteriv", _O(PointParameteriv) }, { "glActiveStencilFaceEXT", _O(ActiveStencilFaceEXT) }, - { "glBindVertexArrayAPPLE", _O(BindVertexArrayAPPLE) }, { "glDeleteVertexArrays", _O(DeleteVertexArrays) }, - { "glGenVertexArraysAPPLE", _O(GenVertexArraysAPPLE) }, { "glIsVertexArray", _O(IsVertexArray) }, { "glGetProgramNamedParameterdvNV", _O(GetProgramNamedParameterdvNV) }, { "glGetProgramNamedParameterfvNV", _O(GetProgramNamedParameterfvNV) }, diff --git a/lib/mesa/src/mapi/shared-glapi/tests/check_table.cpp b/lib/mesa/src/mapi/shared-glapi/tests/check_table.cpp index 02d313c22..314e6769b 100644 --- a/lib/mesa/src/mapi/shared-glapi/tests/check_table.cpp +++ b/lib/mesa/src/mapi/shared-glapi/tests/check_table.cpp @@ -25,7 +25,7 @@ #include "../../../mesa/main/glheader.h" #include "glapi/glapi.h" -#include "glapi/glapitable.h" +#include "glapitable.h" struct name_offset { const char *name; diff --git a/lib/mesa/src/mesa/drivers/dri/i915/intel_screen.h b/lib/mesa/src/mesa/drivers/dri/i915/intel_screen.h index 11e1a3fa3..a22888b39 100644 --- a/lib/mesa/src/mesa/drivers/dri/i915/intel_screen.h +++ b/lib/mesa/src/mesa/drivers/dri/i915/intel_screen.h @@ -33,7 +33,7 @@ #include "dri_util.h" #include "intel_bufmgr.h" #include "i915_drm.h" -#include "xmlconfig.h" +#include "util/xmlconfig.h" struct intel_screen { diff --git a/lib/mesa/src/mesa/drivers/dri/i965/brw_pipe_control.h b/lib/mesa/src/mesa/drivers/dri/i965/brw_pipe_control.h new file mode 100644 index 000000000..6e9a40487 --- /dev/null +++ b/lib/mesa/src/mesa/drivers/dri/i965/brw_pipe_control.h @@ -0,0 +1,89 @@ +/* + * Copyright © 2017 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. + */ + +#ifndef BRW_PIPE_CONTROL_DOT_H +#define BRW_PIPE_CONTROL_DOT_H + +struct brw_context; +struct gen_device_info; +struct brw_bo; + +/** @{ + * + * PIPE_CONTROL operation, a combination MI_FLUSH and register write with + * additional flushing control. + */ +#define _3DSTATE_PIPE_CONTROL (CMD_3D | (3 << 27) | (2 << 24)) +#define PIPE_CONTROL_CS_STALL (1 << 20) +#define PIPE_CONTROL_GLOBAL_SNAPSHOT_COUNT_RESET (1 << 19) +#define PIPE_CONTROL_TLB_INVALIDATE (1 << 18) +#define PIPE_CONTROL_SYNC_GFDT (1 << 17) +#define PIPE_CONTROL_MEDIA_STATE_CLEAR (1 << 16) +#define PIPE_CONTROL_NO_WRITE (0 << 14) +#define PIPE_CONTROL_WRITE_IMMEDIATE (1 << 14) +#define PIPE_CONTROL_WRITE_DEPTH_COUNT (2 << 14) +#define PIPE_CONTROL_WRITE_TIMESTAMP (3 << 14) +#define PIPE_CONTROL_DEPTH_STALL (1 << 13) +#define PIPE_CONTROL_RENDER_TARGET_FLUSH (1 << 12) +#define PIPE_CONTROL_INSTRUCTION_INVALIDATE (1 << 11) +#define PIPE_CONTROL_TEXTURE_CACHE_INVALIDATE (1 << 10) /* GM45+ only */ +#define PIPE_CONTROL_ISP_DIS (1 << 9) +#define PIPE_CONTROL_INTERRUPT_ENABLE (1 << 8) +#define PIPE_CONTROL_FLUSH_ENABLE (1 << 7) /* Gen7+ only */ +/* GT */ +#define PIPE_CONTROL_DATA_CACHE_FLUSH (1 << 5) +#define PIPE_CONTROL_VF_CACHE_INVALIDATE (1 << 4) +#define PIPE_CONTROL_CONST_CACHE_INVALIDATE (1 << 3) +#define PIPE_CONTROL_STATE_CACHE_INVALIDATE (1 << 2) +#define PIPE_CONTROL_STALL_AT_SCOREBOARD (1 << 1) +#define PIPE_CONTROL_DEPTH_CACHE_FLUSH (1 << 0) +#define PIPE_CONTROL_PPGTT_WRITE (0 << 2) +#define PIPE_CONTROL_GLOBAL_GTT_WRITE (1 << 2) + +#define PIPE_CONTROL_CACHE_FLUSH_BITS \ + (PIPE_CONTROL_DEPTH_CACHE_FLUSH | PIPE_CONTROL_DATA_CACHE_FLUSH | \ + PIPE_CONTROL_RENDER_TARGET_FLUSH) + +#define PIPE_CONTROL_CACHE_INVALIDATE_BITS \ + (PIPE_CONTROL_STATE_CACHE_INVALIDATE | PIPE_CONTROL_CONST_CACHE_INVALIDATE | \ + PIPE_CONTROL_VF_CACHE_INVALIDATE | PIPE_CONTROL_TEXTURE_CACHE_INVALIDATE | \ + PIPE_CONTROL_INSTRUCTION_INVALIDATE) + +/** @} */ + +int brw_init_pipe_control(struct brw_context *brw, + const struct gen_device_info *info); +void brw_fini_pipe_control(struct brw_context *brw); + +void brw_emit_pipe_control_flush(struct brw_context *brw, uint32_t flags); +void brw_emit_pipe_control_write(struct brw_context *brw, uint32_t flags, + struct brw_bo *bo, uint32_t offset, + uint64_t imm); +void brw_emit_end_of_pipe_sync(struct brw_context *brw, uint32_t flags); +void brw_emit_mi_flush(struct brw_context *brw); +void brw_emit_post_sync_nonzero_flush(struct brw_context *brw); +void brw_emit_depth_stall_flushes(struct brw_context *brw); +void gen7_emit_vs_workaround_flush(struct brw_context *brw); +void gen7_emit_cs_stall_flush(struct brw_context *brw); + +#endif diff --git a/lib/mesa/src/mesa/drivers/dri/i965/hsw_sol.c b/lib/mesa/src/mesa/drivers/dri/i965/hsw_sol.c index b0dd150b7..f84063ded 100644 --- a/lib/mesa/src/mesa/drivers/dri/i965/hsw_sol.c +++ b/lib/mesa/src/mesa/drivers/dri/i965/hsw_sol.c @@ -92,14 +92,10 @@ tally_prims_written(struct brw_context *brw, /* GPR0 = Tally */ brw_load_register_imm32(brw, HSW_CS_GPR(0) + 4, 0); brw_load_register_mem(brw, HSW_CS_GPR(0), obj->prim_count_bo, - I915_GEM_DOMAIN_INSTRUCTION, - I915_GEM_DOMAIN_INSTRUCTION, TALLY_OFFSET + i * sizeof(uint32_t)); if (!obj->base.Paused) { /* GPR1 = Start Snapshot */ brw_load_register_mem64(brw, HSW_CS_GPR(1), obj->prim_count_bo, - I915_GEM_DOMAIN_INSTRUCTION, - I915_GEM_DOMAIN_INSTRUCTION, START_OFFSET + i * sizeof(uint64_t)); /* GPR2 = Ending Snapshot */ brw_load_register_reg64(brw, GEN7_SO_NUM_PRIMS_WRITTEN(i), HSW_CS_GPR(2)); @@ -165,11 +161,12 @@ hsw_begin_transform_feedback(struct gl_context *ctx, GLenum mode, struct brw_context *brw = brw_context(ctx); struct brw_transform_feedback_object *brw_obj = (struct brw_transform_feedback_object *) obj; + const struct gen_device_info *devinfo = &brw->screen->devinfo; brw_obj->primitive_mode = mode; /* Reset the SO buffer offsets to 0. */ - if (brw->gen >= 8) { + if (devinfo->gen >= 8) { brw_obj->zero_offsets = true; } else { BEGIN_BATCH(1 + 2 * BRW_MAX_XFB_STREAMS); @@ -199,8 +196,9 @@ hsw_pause_transform_feedback(struct gl_context *ctx, struct brw_context *brw = brw_context(ctx); struct brw_transform_feedback_object *brw_obj = (struct brw_transform_feedback_object *) obj; + const struct gen_device_info *devinfo = &brw->screen->devinfo; - if (brw->is_haswell) { + if (devinfo->is_haswell) { /* Flush any drawing so that the counters have the right values. */ brw_emit_mi_flush(brw); @@ -209,9 +207,7 @@ hsw_pause_transform_feedback(struct gl_context *ctx, BEGIN_BATCH(3); OUT_BATCH(MI_STORE_REGISTER_MEM | (3 - 2)); OUT_BATCH(GEN7_SO_WRITE_OFFSET(i)); - OUT_RELOC(brw_obj->offset_bo, - I915_GEM_DOMAIN_INSTRUCTION, I915_GEM_DOMAIN_INSTRUCTION, - i * sizeof(uint32_t)); + OUT_RELOC(brw_obj->offset_bo, RELOC_WRITE, i * sizeof(uint32_t)); ADVANCE_BATCH(); } } @@ -230,16 +226,15 @@ hsw_resume_transform_feedback(struct gl_context *ctx, struct brw_context *brw = brw_context(ctx); struct brw_transform_feedback_object *brw_obj = (struct brw_transform_feedback_object *) obj; + const struct gen_device_info *devinfo = &brw->screen->devinfo; - if (brw->is_haswell) { + if (devinfo->is_haswell) { /* Reload the SOL buffer offset registers. */ for (int i = 0; i < BRW_MAX_XFB_STREAMS; i++) { BEGIN_BATCH(3); OUT_BATCH(GEN7_MI_LOAD_REGISTER_MEM | (3 - 2)); OUT_BATCH(GEN7_SO_WRITE_OFFSET(i)); - OUT_RELOC(brw_obj->offset_bo, - I915_GEM_DOMAIN_INSTRUCTION, I915_GEM_DOMAIN_INSTRUCTION, - i * sizeof(uint32_t)); + OUT_RELOC(brw_obj->offset_bo, RELOC_WRITE, i * sizeof(uint32_t)); ADVANCE_BATCH(); } } diff --git a/lib/mesa/src/mesa/drivers/dri/i965/intel_tex.h b/lib/mesa/src/mesa/drivers/dri/i965/intel_tex.h index 376f075c9..42565baeb 100644 --- a/lib/mesa/src/mesa/drivers/dri/i965/intel_tex.h +++ b/lib/mesa/src/mesa/drivers/dri/i965/intel_tex.h @@ -29,13 +29,12 @@ #include "main/mtypes.h" #include "main/formats.h" #include "brw_context.h" +#include "intel_mipmap_tree.h" void intelInitTextureFuncs(struct dd_function_table *functions); void intelInitTextureImageFuncs(struct dd_function_table *functions); -void intelInitTextureSubImageFuncs(struct dd_function_table *functions); - void intelInitTextureCopyImageFuncs(struct dd_function_table *functions); void intelInitCopyImageFuncs(struct dd_function_table *functions); @@ -49,28 +48,8 @@ struct intel_mipmap_tree * intel_miptree_create_for_teximage(struct brw_context *brw, struct intel_texture_object *intelObj, struct intel_texture_image *intelImage, - uint32_t layout_flags); + enum intel_miptree_create_flags flags); void intel_finalize_mipmap_tree(struct brw_context *brw, GLuint unit); -bool -intel_texsubimage_tiled_memcpy(struct gl_context *ctx, - GLuint dims, - struct gl_texture_image *texImage, - GLint xoffset, GLint yoffset, GLint zoffset, - GLsizei width, GLsizei height, GLsizei depth, - GLenum format, GLenum type, - const GLvoid *pixels, - const struct gl_pixelstore_attrib *packing, - bool for_glTexImage); - -bool -intel_gettexsubimage_tiled_memcpy(struct gl_context *ctx, - struct gl_texture_image *texImage, - GLint xoffset, GLint yofset, - GLsizei width, GLsizei height, - GLenum format, GLenum type, - GLvoid *pixels, - const struct gl_pixelstore_attrib *packing); - #endif diff --git a/lib/mesa/src/mesa/drivers/dri/nouveau/nouveau_context.h b/lib/mesa/src/mesa/drivers/dri/nouveau/nouveau_context.h index b6cbde44a..6ab865c7b 100644 --- a/lib/mesa/src/mesa/drivers/dri/nouveau/nouveau_context.h +++ b/lib/mesa/src/mesa/drivers/dri/nouveau/nouveau_context.h @@ -111,8 +111,8 @@ GLboolean nouveau_context_create(gl_api api, const struct gl_config *visual, __DRIcontext *dri_ctx, unsigned major_version, unsigned minor_version, - uint32_t flags, bool notify_reset, unsigned *error, - void *share_ctx); + uint32_t flags, bool notify_reset, unsigned priority, + unsigned *error, void *share_ctx); GLboolean nouveau_context_init(struct gl_context *ctx, gl_api api, diff --git a/lib/mesa/src/mesa/drivers/dri/nouveau/nv10_context.c b/lib/mesa/src/mesa/drivers/dri/nouveau/nv10_context.c index 7a86ba235..be2178fb7 100644 --- a/lib/mesa/src/mesa/drivers/dri/nouveau/nv10_context.c +++ b/lib/mesa/src/mesa/drivers/dri/nouveau/nv10_context.c @@ -451,10 +451,8 @@ nv10_context_create(struct nouveau_screen *screen, gl_api api, ctx->Extensions.EXT_texture_env_dot3 = true; ctx->Extensions.NV_fog_distance = true; ctx->Extensions.NV_texture_rectangle = true; - if (ctx->Mesa_DXTn) { - ctx->Extensions.EXT_texture_compression_s3tc = true; - ctx->Extensions.ANGLE_texture_compression_dxt = true; - } + ctx->Extensions.EXT_texture_compression_s3tc = true; + ctx->Extensions.ANGLE_texture_compression_dxt = true; /* GL constants. */ ctx->Const.MaxTextureLevels = 12; diff --git a/lib/mesa/src/mesa/drivers/dri/nouveau/nv20_context.c b/lib/mesa/src/mesa/drivers/dri/nouveau/nv20_context.c index ec638c036..0ab2db0b0 100644 --- a/lib/mesa/src/mesa/drivers/dri/nouveau/nv20_context.c +++ b/lib/mesa/src/mesa/drivers/dri/nouveau/nv20_context.c @@ -462,10 +462,8 @@ nv20_context_create(struct nouveau_screen *screen, gl_api api, ctx->Extensions.EXT_texture_env_dot3 = true; ctx->Extensions.NV_fog_distance = true; ctx->Extensions.NV_texture_rectangle = true; - if (ctx->Mesa_DXTn) { - ctx->Extensions.EXT_texture_compression_s3tc = true; - ctx->Extensions.ANGLE_texture_compression_dxt = true; - } + ctx->Extensions.EXT_texture_compression_s3tc = true; + ctx->Extensions.ANGLE_texture_compression_dxt = true; /* GL constants. */ ctx->Const.MaxTextureCoordUnits = NV20_TEXTURE_UNITS; diff --git a/lib/mesa/src/mesa/drivers/dri/r200/Makefile.am b/lib/mesa/src/mesa/drivers/dri/r200/Makefile.am index 1094343d6..110c02ed2 100644 --- a/lib/mesa/src/mesa/drivers/dri/r200/Makefile.am +++ b/lib/mesa/src/mesa/drivers/dri/r200/Makefile.am @@ -34,7 +34,7 @@ AM_CFLAGS = \ -I$(top_srcdir)/src/mesa/ \ -I$(top_srcdir)/src/gallium/include \ -I$(top_srcdir)/src/gallium/auxiliary \ - -I$(top_builddir)/src/mesa/drivers/dri/common \ + -I$(top_builddir)/src/util \ -I$(top_srcdir)/src/mesa/drivers/dri/common \ -I$(top_srcdir)/src/mesa/drivers/dri/r200/server \ $(DEFINES) \ diff --git a/lib/mesa/src/mesa/drivers/dri/r200/radeon_screen.h b/lib/mesa/src/mesa/drivers/dri/r200/radeon_screen.h index b3e926798..e70e334ab 100644 --- a/lib/mesa/src/mesa/drivers/dri/r200/radeon_screen.h +++ b/lib/mesa/src/mesa/drivers/dri/r200/radeon_screen.h @@ -45,7 +45,7 @@ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. #include "dri_util.h" #include "radeon_chipset.h" #include "radeon_reg.h" -#include "xmlconfig.h" +#include "util/xmlconfig.h" typedef struct { diff --git a/lib/mesa/src/mesa/drivers/dri/r200/radeon_texture.c b/lib/mesa/src/mesa/drivers/dri/r200/radeon_texture.c index 4794ddae0..f2d435a37 100644 --- a/lib/mesa/src/mesa/drivers/dri/r200/radeon_texture.c +++ b/lib/mesa/src/mesa/drivers/dri/r200/radeon_texture.c @@ -41,7 +41,7 @@ #include "main/texobj.h" #include "drivers/common/meta.h" -#include "xmlpool.h" /* for symbolic values of enum-type options */ +#include "util/xmlpool.h" /* for symbolic values of enum-type options */ #include "radeon_common.h" diff --git a/lib/mesa/src/mesa/drivers/dri/radeon/Makefile.am b/lib/mesa/src/mesa/drivers/dri/radeon/Makefile.am index 176ec797e..aa898645c 100644 --- a/lib/mesa/src/mesa/drivers/dri/radeon/Makefile.am +++ b/lib/mesa/src/mesa/drivers/dri/radeon/Makefile.am @@ -35,7 +35,7 @@ AM_CFLAGS = \ -I$(top_srcdir)/src/mesa/ \ -I$(top_srcdir)/src/gallium/include \ -I$(top_srcdir)/src/gallium/auxiliary \ - -I$(top_builddir)/src/mesa/drivers/dri/common \ + -I$(top_builddir)/src/util \ -I$(top_srcdir)/src/mesa/drivers/dri/common \ -I$(top_srcdir)/src/mesa/drivers/dri/radeon/server \ $(DEFINES) \ diff --git a/lib/mesa/src/mesa/drivers/dri/radeon/radeon_context.h b/lib/mesa/src/mesa/drivers/dri/radeon/radeon_context.h index 88a295386..4124f50db 100644 --- a/lib/mesa/src/mesa/drivers/dri/radeon/radeon_context.h +++ b/lib/mesa/src/mesa/drivers/dri/radeon/radeon_context.h @@ -456,6 +456,7 @@ extern GLboolean r100CreateContext( gl_api api, unsigned minor_version, uint32_t flags, bool notify_reset, + unsigned priority, unsigned *error, void *sharedContextPrivate); diff --git a/lib/mesa/src/mesa/drivers/dri/radeon/radeon_screen.h b/lib/mesa/src/mesa/drivers/dri/radeon/radeon_screen.h index b3e926798..e70e334ab 100644 --- a/lib/mesa/src/mesa/drivers/dri/radeon/radeon_screen.h +++ b/lib/mesa/src/mesa/drivers/dri/radeon/radeon_screen.h @@ -45,7 +45,7 @@ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. #include "dri_util.h" #include "radeon_chipset.h" #include "radeon_reg.h" -#include "xmlconfig.h" +#include "util/xmlconfig.h" typedef struct { diff --git a/lib/mesa/src/mesa/drivers/dri/radeon/radeon_state_init.c b/lib/mesa/src/mesa/drivers/dri/radeon/radeon_state_init.c index 5e2f41fdb..99c535a49 100644 --- a/lib/mesa/src/mesa/drivers/dri/radeon/radeon_state_init.c +++ b/lib/mesa/src/mesa/drivers/dri/radeon/radeon_state_init.c @@ -44,7 +44,7 @@ #include "../r200/r200_reg.h" -#include "xmlpool.h" +#include "util/xmlpool.h" /* New (1.3) state mechanism. 3 commands (packet, scalar, vector) in * 1.3 cmdbuffers allow all previous state to be updated as well as diff --git a/lib/mesa/src/mesa/drivers/dri/radeon/radeon_tcl.c b/lib/mesa/src/mesa/drivers/dri/radeon/radeon_tcl.c index 3e2f42616..61ff2311e 100644 --- a/lib/mesa/src/mesa/drivers/dri/radeon/radeon_tcl.c +++ b/lib/mesa/src/mesa/drivers/dri/radeon/radeon_tcl.c @@ -39,6 +39,8 @@ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. #include "main/enums.h" #include "main/state.h" +#include "util/macros.h" + #include "vbo/vbo.h" #include "tnl/tnl.h" #include "tnl/t_pipeline.h" @@ -297,7 +299,7 @@ static GLuint radeonEnsureEmitSize( struct gl_context * ctx , GLuint inputs ) VERT_BIT_FOG }; /* predict number of aos to emit */ - for (i=0; i < sizeof(flags_to_check)/sizeof(flags_to_check[0]); ++i) + for (i=0; i < ARRAY_SIZE(flags_to_check); ++i) { if (inputs & flags_to_check[i]) ++nr_aos; diff --git a/lib/mesa/src/mesa/drivers/dri/radeon/radeon_texture.c b/lib/mesa/src/mesa/drivers/dri/radeon/radeon_texture.c index 4794ddae0..f2d435a37 100644 --- a/lib/mesa/src/mesa/drivers/dri/radeon/radeon_texture.c +++ b/lib/mesa/src/mesa/drivers/dri/radeon/radeon_texture.c @@ -41,7 +41,7 @@ #include "main/texobj.h" #include "drivers/common/meta.h" -#include "xmlpool.h" /* for symbolic values of enum-type options */ +#include "util/xmlpool.h" /* for symbolic values of enum-type options */ #include "radeon_common.h" diff --git a/lib/mesa/src/mesa/drivers/dri/swrast/Makefile.am b/lib/mesa/src/mesa/drivers/dri/swrast/Makefile.am index a82e580f1..7e1ea59e9 100644 --- a/lib/mesa/src/mesa/drivers/dri/swrast/Makefile.am +++ b/lib/mesa/src/mesa/drivers/dri/swrast/Makefile.am @@ -30,7 +30,7 @@ AM_CFLAGS = \ -I$(top_srcdir)/src/mesa/ \ -I$(top_srcdir)/src/gallium/include \ -I$(top_srcdir)/src/gallium/auxiliary \ - -I$(top_builddir)/src/mesa/drivers/dri/common \ + -I$(top_builddir)/src/util \ -I$(top_srcdir)/src/mesa/drivers/dri/common \ $(LIBDRM_CFLAGS) \ $(DEFINES) \ diff --git a/lib/mesa/src/mesa/swrast/s_texfetch.c b/lib/mesa/src/mesa/swrast/s_texfetch.c index 4353ea0e4..e2c3c085b 100644 --- a/lib/mesa/src/mesa/swrast/s_texfetch.c +++ b/lib/mesa/src/mesa/swrast/s_texfetch.c @@ -159,6 +159,7 @@ texfetch_funcs[] = FETCH_NULL(B4G4R4X4_UNORM), FETCH_FUNCS(A4R4G4B4_UNORM), FETCH_FUNCS(A1B5G5R5_UNORM), + FETCH_NULL(X1B5G5R5_UNORM), FETCH_FUNCS(B5G5R5A1_UNORM), FETCH_NULL(B5G5R5X1_UNORM), FETCH_FUNCS(A1R5G5B5_UNORM), |