static int emit_vs_consts( struct svga_context *svga, unsigned dirty ) { const struct svga_shader_result *result = svga->state.hw_draw.vs; const struct svga_vs_compile_key *key = &result->key.vkey; int ret = 0; unsigned offset; /* SVGA_NEW_VS_RESULT */ if (result == NULL) return 0; /* SVGA_NEW_VS_CONST_BUFFER */ ret = emit_consts( svga, 0, PIPE_SHADER_VERTEX ); if (ret) return ret; offset = result->shader->info.file_max[TGSI_FILE_CONSTANT] + 1; /* SVGA_NEW_VS_RESULT */ if (key->need_prescale) { ret = emit_const( svga, PIPE_SHADER_VERTEX, offset++, svga->state.hw_clear.prescale.scale ); if (ret) return ret; ret = emit_const( svga, PIPE_SHADER_VERTEX, offset++, svga->state.hw_clear.prescale.translate ); if (ret) return ret; } /* SVGA_NEW_ZERO_STRIDE */ if (key->zero_stride_vertex_elements) { unsigned i, curr_zero_stride = 0; for (i = 0; i < PIPE_MAX_ATTRIBS; ++i) { if (key->zero_stride_vertex_elements & (1 << i)) { ret = emit_const( svga, PIPE_SHADER_VERTEX, offset++, svga->curr.zero_stride_constants + 4 * curr_zero_stride ); if (ret) return ret; ++curr_zero_stride; } } } return 0; }
static enum pipe_error emit_vs_consts(struct svga_context *svga, unsigned dirty) { const struct svga_shader_result *result = svga->state.hw_draw.vs; const struct svga_vs_compile_key *key; enum pipe_error ret = PIPE_OK; unsigned offset; /* SVGA_NEW_VS_RESULT */ if (result == NULL) return PIPE_OK; key = &result->key.vkey; /* SVGA_NEW_VS_CONST_BUFFER */ ret = emit_consts( svga, PIPE_SHADER_VERTEX ); if (ret != PIPE_OK) return ret; /* offset = number of constants in the VS const buffer */ offset = result->shader->info.file_max[TGSI_FILE_CONSTANT] + 1; /* SVGA_NEW_VS_PRESCALE * Put the viewport pre-scale/translate values into the const buffer. */ if (key->need_prescale) { ret = emit_const( svga, PIPE_SHADER_VERTEX, offset++, svga->state.hw_clear.prescale.scale ); if (ret != PIPE_OK) return ret; ret = emit_const( svga, PIPE_SHADER_VERTEX, offset++, svga->state.hw_clear.prescale.translate ); if (ret != PIPE_OK) return ret; } return PIPE_OK; }
/** * Emit all the constants in a constant buffer for a shader stage. */ static enum pipe_error emit_consts(struct svga_context *svga, unsigned shader) { struct svga_screen *ss = svga_screen(svga->pipe.screen); struct pipe_transfer *transfer = NULL; unsigned count; const float (*data)[4] = NULL; unsigned i; enum pipe_error ret = PIPE_OK; const unsigned offset = 0; assert(shader < PIPE_SHADER_TYPES); if (svga->curr.cb[shader] == NULL) goto done; count = svga->curr.cb[shader]->width0 / (4 * sizeof(float)); data = (const float (*)[4])pipe_buffer_map(&svga->pipe, svga->curr.cb[shader], PIPE_TRANSFER_READ, &transfer); if (data == NULL) { ret = PIPE_ERROR_OUT_OF_MEMORY; goto done; } if (ss->hw_version >= SVGA3D_HWVERSION_WS8_B1) { ret = emit_const_range( svga, shader, offset, count, data ); if (ret != PIPE_OK) { goto done; } } else { for (i = 0; i < count; i++) { ret = emit_const( svga, shader, offset + i, data[i] ); if (ret != PIPE_OK) { goto done; } } } done: if (data) pipe_buffer_unmap(&svga->pipe, transfer); return ret; }
static int emit_fs_consts( struct svga_context *svga, unsigned dirty ) { const struct svga_shader_result *result = svga->state.hw_draw.fs; const struct svga_fs_compile_key *key = &result->key.fkey; int ret = 0; ret = emit_consts( svga, 0, PIPE_SHADER_FRAGMENT ); if (ret) return ret; /* The internally generated fragment shader for xor blending * doesn't have a 'result' struct. It should be fixed to avoid * this special case, but work around it with a NULL check: */ if (result != NULL && key->num_unnormalized_coords) { unsigned offset = result->shader->info.file_max[TGSI_FILE_CONSTANT] + 1; int i; for (i = 0; i < key->num_textures; i++) { if (key->tex[i].unnormalized) { struct pipe_resource *tex = svga->curr.sampler_views[i]->texture; float data[4]; data[0] = 1.0 / (float)tex->width0; data[1] = 1.0 / (float)tex->height0; data[2] = 1.0; data[3] = 1.0; ret = emit_const( svga, PIPE_SHADER_FRAGMENT, key->tex[i].width_height_idx + offset, data ); if (ret) return ret; } } offset += key->num_unnormalized_coords; } return 0; }
static int emit_consts( struct svga_context *svga, int offset, int unit ) { struct pipe_transfer *transfer = NULL; unsigned count; const float (*data)[4] = NULL; unsigned i; int ret = PIPE_OK; if (svga->curr.cb[unit] == NULL) goto done; count = svga->curr.cb[unit]->width0 / (4 * sizeof(float)); data = (const float (*)[4])pipe_buffer_map(&svga->pipe, svga->curr.cb[unit], PIPE_TRANSFER_READ, &transfer); if (data == NULL) { ret = PIPE_ERROR_OUT_OF_MEMORY; goto done; } for (i = 0; i < count; i++) { ret = emit_const( svga, unit, offset + i, data[i] ); if (ret) goto done; } done: if (data) pipe_buffer_unmap(&svga->pipe, svga->curr.cb[unit], transfer); return ret; }
enum eval_result_type compile_bytecodes (struct agent_expr *aexpr) { int pc = 0; int done = 0; unsigned char op, next_op; int arg; /* This is only used to build 64-bit value for constants. */ ULONGEST top; struct bytecode_address *aentry, *aentry2; #define UNHANDLED \ do \ { \ ax_debug ("Cannot compile op 0x%x\n", op); \ return expr_eval_unhandled_opcode; \ } while (0) if (aexpr->length == 0) { ax_debug ("empty agent expression\n"); return expr_eval_empty_expression; } bytecode_address_table = NULL; while (!done) { op = aexpr->bytes[pc]; ax_debug ("About to compile op 0x%x, pc=%d\n", op, pc); /* Record the compiled-code address of the bytecode, for use by jump instructions. */ aentry = XNEW (struct bytecode_address); aentry->pc = pc; aentry->address = current_insn_ptr; aentry->goto_pc = -1; aentry->from_offset = aentry->from_size = 0; aentry->next = bytecode_address_table; bytecode_address_table = aentry; ++pc; emit_error = 0; switch (op) { case gdb_agent_op_add: emit_add (); break; case gdb_agent_op_sub: emit_sub (); break; case gdb_agent_op_mul: emit_mul (); break; case gdb_agent_op_div_signed: UNHANDLED; break; case gdb_agent_op_div_unsigned: UNHANDLED; break; case gdb_agent_op_rem_signed: UNHANDLED; break; case gdb_agent_op_rem_unsigned: UNHANDLED; break; case gdb_agent_op_lsh: emit_lsh (); break; case gdb_agent_op_rsh_signed: emit_rsh_signed (); break; case gdb_agent_op_rsh_unsigned: emit_rsh_unsigned (); break; case gdb_agent_op_trace: UNHANDLED; break; case gdb_agent_op_trace_quick: UNHANDLED; break; case gdb_agent_op_log_not: emit_log_not (); break; case gdb_agent_op_bit_and: emit_bit_and (); break; case gdb_agent_op_bit_or: emit_bit_or (); break; case gdb_agent_op_bit_xor: emit_bit_xor (); break; case gdb_agent_op_bit_not: emit_bit_not (); break; case gdb_agent_op_equal: next_op = aexpr->bytes[pc]; if (next_op == gdb_agent_op_if_goto && !is_goto_target (aexpr, pc) && target_emit_ops ()->emit_eq_goto) { ax_debug ("Combining equal & if_goto"); pc += 1; aentry->pc = pc; arg = aexpr->bytes[pc++]; arg = (arg << 8) + aexpr->bytes[pc++]; aentry->goto_pc = arg; emit_eq_goto (&(aentry->from_offset), &(aentry->from_size)); } else if (next_op == gdb_agent_op_log_not && (aexpr->bytes[pc + 1] == gdb_agent_op_if_goto) && !is_goto_target (aexpr, pc + 1) && target_emit_ops ()->emit_ne_goto) { ax_debug ("Combining equal & log_not & if_goto"); pc += 2; aentry->pc = pc; arg = aexpr->bytes[pc++]; arg = (arg << 8) + aexpr->bytes[pc++]; aentry->goto_pc = arg; emit_ne_goto (&(aentry->from_offset), &(aentry->from_size)); } else emit_equal (); break; case gdb_agent_op_less_signed: next_op = aexpr->bytes[pc]; if (next_op == gdb_agent_op_if_goto && !is_goto_target (aexpr, pc)) { ax_debug ("Combining less_signed & if_goto"); pc += 1; aentry->pc = pc; arg = aexpr->bytes[pc++]; arg = (arg << 8) + aexpr->bytes[pc++]; aentry->goto_pc = arg; emit_lt_goto (&(aentry->from_offset), &(aentry->from_size)); } else if (next_op == gdb_agent_op_log_not && !is_goto_target (aexpr, pc) && (aexpr->bytes[pc + 1] == gdb_agent_op_if_goto) && !is_goto_target (aexpr, pc + 1)) { ax_debug ("Combining less_signed & log_not & if_goto"); pc += 2; aentry->pc = pc; arg = aexpr->bytes[pc++]; arg = (arg << 8) + aexpr->bytes[pc++]; aentry->goto_pc = arg; emit_ge_goto (&(aentry->from_offset), &(aentry->from_size)); } else emit_less_signed (); break; case gdb_agent_op_less_unsigned: emit_less_unsigned (); break; case gdb_agent_op_ext: arg = aexpr->bytes[pc++]; if (arg < (sizeof (LONGEST) * 8)) emit_ext (arg); break; case gdb_agent_op_ref8: emit_ref (1); break; case gdb_agent_op_ref16: emit_ref (2); break; case gdb_agent_op_ref32: emit_ref (4); break; case gdb_agent_op_ref64: emit_ref (8); break; case gdb_agent_op_if_goto: arg = aexpr->bytes[pc++]; arg = (arg << 8) + aexpr->bytes[pc++]; aentry->goto_pc = arg; emit_if_goto (&(aentry->from_offset), &(aentry->from_size)); break; case gdb_agent_op_goto: arg = aexpr->bytes[pc++]; arg = (arg << 8) + aexpr->bytes[pc++]; aentry->goto_pc = arg; emit_goto (&(aentry->from_offset), &(aentry->from_size)); break; case gdb_agent_op_const8: emit_stack_flush (); top = aexpr->bytes[pc++]; emit_const (top); break; case gdb_agent_op_const16: emit_stack_flush (); top = aexpr->bytes[pc++]; top = (top << 8) + aexpr->bytes[pc++]; emit_const (top); break; case gdb_agent_op_const32: emit_stack_flush (); top = aexpr->bytes[pc++]; top = (top << 8) + aexpr->bytes[pc++]; top = (top << 8) + aexpr->bytes[pc++]; top = (top << 8) + aexpr->bytes[pc++]; emit_const (top); break; case gdb_agent_op_const64: emit_stack_flush (); top = aexpr->bytes[pc++]; top = (top << 8) + aexpr->bytes[pc++]; top = (top << 8) + aexpr->bytes[pc++]; top = (top << 8) + aexpr->bytes[pc++]; top = (top << 8) + aexpr->bytes[pc++]; top = (top << 8) + aexpr->bytes[pc++]; top = (top << 8) + aexpr->bytes[pc++]; top = (top << 8) + aexpr->bytes[pc++]; emit_const (top); break; case gdb_agent_op_reg: emit_stack_flush (); arg = aexpr->bytes[pc++]; arg = (arg << 8) + aexpr->bytes[pc++]; emit_reg (arg); break; case gdb_agent_op_end: ax_debug ("At end of expression\n"); /* Assume there is one stack element left, and that it is cached in "top" where emit_epilogue can get to it. */ emit_stack_adjust (1); done = 1; break; case gdb_agent_op_dup: /* In our design, dup is equivalent to stack flushing. */ emit_stack_flush (); break; case gdb_agent_op_pop: emit_pop (); break; case gdb_agent_op_zero_ext: arg = aexpr->bytes[pc++]; if (arg < (sizeof (LONGEST) * 8)) emit_zero_ext (arg); break; case gdb_agent_op_swap: next_op = aexpr->bytes[pc]; /* Detect greater-than comparison sequences. */ if (next_op == gdb_agent_op_less_signed && !is_goto_target (aexpr, pc) && (aexpr->bytes[pc + 1] == gdb_agent_op_if_goto) && !is_goto_target (aexpr, pc + 1)) { ax_debug ("Combining swap & less_signed & if_goto"); pc += 2; aentry->pc = pc; arg = aexpr->bytes[pc++]; arg = (arg << 8) + aexpr->bytes[pc++]; aentry->goto_pc = arg; emit_gt_goto (&(aentry->from_offset), &(aentry->from_size)); } else if (next_op == gdb_agent_op_less_signed && !is_goto_target (aexpr, pc) && (aexpr->bytes[pc + 1] == gdb_agent_op_log_not) && !is_goto_target (aexpr, pc + 1) && (aexpr->bytes[pc + 2] == gdb_agent_op_if_goto) && !is_goto_target (aexpr, pc + 2)) { ax_debug ("Combining swap & less_signed & log_not & if_goto"); pc += 3; aentry->pc = pc; arg = aexpr->bytes[pc++]; arg = (arg << 8) + aexpr->bytes[pc++]; aentry->goto_pc = arg; emit_le_goto (&(aentry->from_offset), &(aentry->from_size)); } else emit_swap (); break; case gdb_agent_op_getv: emit_stack_flush (); arg = aexpr->bytes[pc++]; arg = (arg << 8) + aexpr->bytes[pc++]; emit_int_call_1 (get_get_tsv_func_addr (), arg); break; case gdb_agent_op_setv: arg = aexpr->bytes[pc++]; arg = (arg << 8) + aexpr->bytes[pc++]; emit_void_call_2 (get_set_tsv_func_addr (), arg); break; case gdb_agent_op_tracev: UNHANDLED; break; /* GDB never (currently) generates any of these ops. */ case gdb_agent_op_float: case gdb_agent_op_ref_float: case gdb_agent_op_ref_double: case gdb_agent_op_ref_long_double: case gdb_agent_op_l_to_d: case gdb_agent_op_d_to_l: case gdb_agent_op_trace16: UNHANDLED; break; default: ax_debug ("Agent expression op 0x%x not recognized\n", op); /* Don't struggle on, things will just get worse. */ return expr_eval_unrecognized_opcode; } /* This catches errors that occur in target-specific code emission. */ if (emit_error) { ax_debug ("Error %d while emitting code for %s\n", emit_error, gdb_agent_op_name (op)); return expr_eval_unhandled_opcode; } ax_debug ("Op %s compiled\n", gdb_agent_op_name (op)); } /* Now fill in real addresses as goto destinations. */ for (aentry = bytecode_address_table; aentry; aentry = aentry->next) { int written = 0; if (aentry->goto_pc < 0) continue; /* Find the location that we are going to, and call back into target-specific code to write the actual address or displacement. */ for (aentry2 = bytecode_address_table; aentry2; aentry2 = aentry2->next) { if (aentry2->pc == aentry->goto_pc) { ax_debug ("Want to jump from %s to %s\n", paddress (aentry->address), paddress (aentry2->address)); write_goto_address (aentry->address + aentry->from_offset, aentry2->address, aentry->from_size); written = 1; break; } } /* Error out if we didn't find a destination. */ if (!written) { ax_debug ("Destination of goto %d not found\n", aentry->goto_pc); return expr_eval_invalid_goto; } } return expr_eval_no_error; }
/** * Emit all the constants in a constant buffer for a shader stage. * On VGPU10, emit_consts_vgpu10 is used instead. */ static enum pipe_error emit_consts_vgpu9(struct svga_context *svga, unsigned shader) { const struct pipe_constant_buffer *cbuf; struct svga_screen *ss = svga_screen(svga->pipe.screen); struct pipe_transfer *transfer = NULL; unsigned count; const float (*data)[4] = NULL; unsigned i; enum pipe_error ret = PIPE_OK; const unsigned offset = 0; assert(shader < PIPE_SHADER_TYPES); assert(!svga_have_vgpu10(svga)); /* Only one constant buffer per shader is supported before VGPU10. * This is only an approximate check against that. */ assert(svga->curr.constbufs[shader][1].buffer == NULL); cbuf = &svga->curr.constbufs[shader][0]; if (svga->curr.constbufs[shader][0].buffer) { /* emit user-provided constants */ data = (const float (*)[4]) pipe_buffer_map(&svga->pipe, svga->curr.constbufs[shader][0].buffer, PIPE_TRANSFER_READ, &transfer); if (!data) { return PIPE_ERROR_OUT_OF_MEMORY; } /* sanity check */ assert(cbuf->buffer->width0 >= cbuf->buffer_size); /* Use/apply the constant buffer size and offsets here */ count = cbuf->buffer_size / (4 * sizeof(float)); data += cbuf->buffer_offset / (4 * sizeof(float)); if (ss->hw_version >= SVGA3D_HWVERSION_WS8_B1) { ret = emit_const_range( svga, shader, offset, count, data ); } else { for (i = 0; i < count; i++) { ret = emit_const( svga, shader, offset + i, data[i] ); if (ret != PIPE_OK) { break; } } } pipe_buffer_unmap(&svga->pipe, transfer); if (ret != PIPE_OK) { return ret; } } /* emit extra shader constants */ { const struct svga_shader_variant *variant = NULL; unsigned offset; float extras[MAX_EXTRA_CONSTS][4]; unsigned count, i; switch (shader) { case PIPE_SHADER_VERTEX: variant = svga->state.hw_draw.vs; count = svga_get_extra_vs_constants(svga, (float *) extras); break; case PIPE_SHADER_FRAGMENT: variant = svga->state.hw_draw.fs; count = svga_get_extra_fs_constants(svga, (float *) extras); break; default: assert(!"Unexpected shader type"); count = 0; } assert(variant); offset = variant->shader->info.file_max[TGSI_FILE_CONSTANT] + 1; assert(count <= ARRAY_SIZE(extras)); if (count > 0) { if (ss->hw_version >= SVGA3D_HWVERSION_WS8_B1) { ret = emit_const_range(svga, shader, offset, count, (const float (*) [4])extras); } else { for (i = 0; i < count; i++) { ret = emit_const(svga, shader, offset + i, extras[i]); if (ret != PIPE_OK) return ret; } } } } return ret; }