| /* |
| Copyright (C) Intel Corp. 2006. All Rights Reserved. |
| Intel funded Tungsten Graphics (http://www.tungstengraphics.com) to |
| develop this 3D driver. |
| |
| 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 COPYRIGHT OWNER(S) AND/OR ITS SUPPLIERS BE |
| LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION |
| OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION |
| WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. |
| |
| **********************************************************************/ |
| /* |
| * Authors: |
| * Keith Whitwell <keith@tungstengraphics.com> |
| */ |
| |
| |
| #include "glheader.h" |
| #include "macros.h" |
| #include "enums.h" |
| |
| #include "shader/program.h" |
| #include "intel_batchbuffer.h" |
| |
| #include "brw_defines.h" |
| #include "brw_context.h" |
| #include "brw_eu.h" |
| #include "brw_util.h" |
| #include "brw_clip.h" |
| |
| |
| |
| |
| struct brw_reg get_tmp( struct brw_clip_compile *c ) |
| { |
| struct brw_reg tmp = brw_vec4_grf(c->last_tmp, 0); |
| |
| if (++c->last_tmp > c->prog_data.total_grf) |
| c->prog_data.total_grf = c->last_tmp; |
| |
| return tmp; |
| } |
| |
| static void release_tmp( struct brw_clip_compile *c, struct brw_reg tmp ) |
| { |
| if (tmp.nr == c->last_tmp-1) |
| c->last_tmp--; |
| } |
| |
| |
| static struct brw_reg make_plane_ud(GLuint x, GLuint y, GLuint z, GLuint w) |
| { |
| return brw_imm_ud((w<<24) | (z<<16) | (y<<8) | x); |
| } |
| |
| |
| void brw_clip_init_planes( struct brw_clip_compile *c ) |
| { |
| struct brw_compile *p = &c->func; |
| |
| if (!c->key.nr_userclip) { |
| brw_MOV(p, get_element_ud(c->reg.fixed_planes, 0), make_plane_ud( 0, 0, 0xff, 1)); |
| brw_MOV(p, get_element_ud(c->reg.fixed_planes, 1), make_plane_ud( 0, 0, 1, 1)); |
| brw_MOV(p, get_element_ud(c->reg.fixed_planes, 2), make_plane_ud( 0, 0xff, 0, 1)); |
| brw_MOV(p, get_element_ud(c->reg.fixed_planes, 3), make_plane_ud( 0, 1, 0, 1)); |
| brw_MOV(p, get_element_ud(c->reg.fixed_planes, 4), make_plane_ud(0xff, 0, 0, 1)); |
| brw_MOV(p, get_element_ud(c->reg.fixed_planes, 5), make_plane_ud( 1, 0, 0, 1)); |
| } |
| } |
| |
| |
| |
| #define W 3 |
| |
| /* Project 'pos' to screen space (or back again), overwrite with results: |
| */ |
| void brw_clip_project_position(struct brw_clip_compile *c, struct brw_reg pos ) |
| { |
| struct brw_compile *p = &c->func; |
| |
| /* calc rhw |
| */ |
| brw_math_invert(p, get_element(pos, W), get_element(pos, W)); |
| |
| /* value.xyz *= value.rhw |
| */ |
| brw_set_access_mode(p, BRW_ALIGN_16); |
| brw_MUL(p, brw_writemask(pos, WRITEMASK_XYZ), pos, brw_swizzle1(pos, W)); |
| brw_set_access_mode(p, BRW_ALIGN_1); |
| } |
| |
| |
| static void brw_clip_project_vertex( struct brw_clip_compile *c, |
| struct brw_indirect vert_addr ) |
| { |
| struct brw_compile *p = &c->func; |
| struct brw_reg tmp = get_tmp(c); |
| |
| /* Fixup position. Extract from the original vertex and re-project |
| * to screen space: |
| */ |
| brw_MOV(p, tmp, deref_4f(vert_addr, c->offset[VERT_RESULT_HPOS])); |
| brw_clip_project_position(c, tmp); |
| brw_MOV(p, deref_4f(vert_addr, c->header_position_offset), tmp); |
| |
| release_tmp(c, tmp); |
| } |
| |
| |
| |
| |
| /* Interpolate between two vertices and put the result into a0.0. |
| * Increment a0.0 accordingly. |
| */ |
| void brw_clip_interp_vertex( struct brw_clip_compile *c, |
| struct brw_indirect dest_ptr, |
| struct brw_indirect v0_ptr, /* from */ |
| struct brw_indirect v1_ptr, /* to */ |
| struct brw_reg t0, |
| GLboolean force_edgeflag) |
| { |
| struct brw_compile *p = &c->func; |
| struct brw_reg tmp = get_tmp(c); |
| GLuint i; |
| |
| /* Just copy the vertex header: |
| */ |
| brw_copy_indirect_to_indirect(p, dest_ptr, v0_ptr, 1); |
| |
| /* Iterate over each attribute (could be done in pairs?) |
| */ |
| for (i = 0; i < c->nr_attrs; i++) { |
| GLuint delta = i*16 + 32; |
| |
| if (delta == c->offset[VERT_RESULT_EDGE]) { |
| if (force_edgeflag) |
| brw_MOV(p, deref_4f(dest_ptr, delta), brw_imm_f(1)); |
| else |
| brw_MOV(p, deref_4f(dest_ptr, delta), deref_4f(v0_ptr, delta)); |
| } |
| else { |
| /* Interpolate: |
| * |
| * New = attr0 + t*attr1 - t*attr0 |
| */ |
| brw_MUL(p, |
| vec4(brw_null_reg()), |
| deref_4f(v1_ptr, delta), |
| t0); |
| |
| brw_MAC(p, |
| tmp, |
| negate(deref_4f(v0_ptr, delta)), |
| t0); |
| |
| brw_ADD(p, |
| deref_4f(dest_ptr, delta), |
| deref_4f(v0_ptr, delta), |
| tmp); |
| } |
| } |
| |
| if (i & 1) { |
| GLuint delta = i*16 + 32; |
| brw_MOV(p, deref_4f(dest_ptr, delta), brw_imm_f(0)); |
| } |
| |
| release_tmp(c, tmp); |
| |
| /* Recreate the projected (NDC) coordinate in the new vertex |
| * header: |
| */ |
| brw_clip_project_vertex(c, dest_ptr ); |
| } |
| |
| |
| |
| |
| #define MAX_MRF 16 |
| |
| void brw_clip_emit_vue(struct brw_clip_compile *c, |
| struct brw_indirect vert, |
| GLboolean allocate, |
| GLboolean eot, |
| GLuint header) |
| { |
| struct brw_compile *p = &c->func; |
| GLuint start = c->last_mrf; |
| |
| assert(!(allocate && eot)); |
| |
| /* Cycle through mrf regs - probably futile as we have to wait for |
| * the allocation response anyway. Also, the order this function |
| * is invoked doesn't correspond to the order the instructions will |
| * be executed, so it won't have any effect in many cases. |
| */ |
| #if 0 |
| if (start + c->nr_regs + 1 >= MAX_MRF) |
| start = 0; |
| |
| c->last_mrf = start + c->nr_regs + 1; |
| #endif |
| |
| /* Copy the vertex from vertn into m1..mN+1: |
| */ |
| brw_copy_from_indirect(p, brw_message_reg(start+1), vert, c->nr_regs); |
| |
| /* Overwrite PrimType and PrimStart in the message header, for |
| * each vertex in turn: |
| */ |
| brw_MOV(p, get_element_ud(c->reg.R0, 2), brw_imm_ud(header)); |
| |
| |
| /* Send each vertex as a seperate write to the urb. This |
| * is different to the concept in brw_sf_emit.c, where |
| * subsequent writes are used to build up a single urb |
| * entry. Each of these writes instantiates a seperate |
| * urb entry - (I think... what about 'allocate'?) |
| */ |
| brw_urb_WRITE(p, |
| allocate ? c->reg.R0 : retype(brw_null_reg(), BRW_REGISTER_TYPE_UD), |
| start, |
| c->reg.R0, |
| allocate, |
| 1, /* used */ |
| c->nr_regs + 1, /* msg length */ |
| allocate ? 1 : 0, /* response_length */ |
| eot, /* eot */ |
| 1, /* writes_complete */ |
| 0, /* urb offset */ |
| BRW_URB_SWIZZLE_NONE); |
| } |
| |
| |
| |
| void brw_clip_kill_thread(struct brw_clip_compile *c) |
| { |
| struct brw_compile *p = &c->func; |
| |
| /* Send an empty message to kill the thread and release any |
| * allocated urb entry: |
| */ |
| brw_urb_WRITE(p, |
| retype(brw_null_reg(), BRW_REGISTER_TYPE_UD), |
| 0, |
| c->reg.R0, |
| 0, /* allocate */ |
| 0, /* used */ |
| 1, /* msg len */ |
| 0, /* response len */ |
| 1, /* eot */ |
| 1, /* writes complete */ |
| 0, |
| BRW_URB_SWIZZLE_NONE); |
| } |
| |
| |
| |
| |
| struct brw_reg brw_clip_plane0_address( struct brw_clip_compile *c ) |
| { |
| return brw_address(c->reg.fixed_planes); |
| } |
| |
| |
| struct brw_reg brw_clip_plane_stride( struct brw_clip_compile *c ) |
| { |
| if (c->key.nr_userclip) { |
| return brw_imm_uw(16); |
| } |
| else { |
| return brw_imm_uw(4); |
| } |
| } |
| |
| |
| /* If flatshading, distribute color from provoking vertex prior to |
| * clipping. |
| */ |
| void brw_clip_copy_colors( struct brw_clip_compile *c, |
| GLuint to, GLuint from ) |
| { |
| struct brw_compile *p = &c->func; |
| |
| if (c->offset[VERT_RESULT_COL0]) |
| brw_MOV(p, |
| byte_offset(c->reg.vertex[to], c->offset[VERT_RESULT_COL0]), |
| byte_offset(c->reg.vertex[from], c->offset[VERT_RESULT_COL0])); |
| |
| if (c->offset[VERT_RESULT_COL1]) |
| brw_MOV(p, |
| byte_offset(c->reg.vertex[to], c->offset[VERT_RESULT_COL1]), |
| byte_offset(c->reg.vertex[from], c->offset[VERT_RESULT_COL1])); |
| |
| if (c->offset[VERT_RESULT_BFC0]) |
| brw_MOV(p, |
| byte_offset(c->reg.vertex[to], c->offset[VERT_RESULT_BFC0]), |
| byte_offset(c->reg.vertex[from], c->offset[VERT_RESULT_BFC0])); |
| |
| if (c->offset[VERT_RESULT_BFC1]) |
| brw_MOV(p, |
| byte_offset(c->reg.vertex[to], c->offset[VERT_RESULT_BFC1]), |
| byte_offset(c->reg.vertex[from], c->offset[VERT_RESULT_BFC1])); |
| } |
| |
| |
| |
| void brw_clip_init_clipmask( struct brw_clip_compile *c ) |
| { |
| struct brw_compile *p = &c->func; |
| struct brw_reg incoming = get_element_ud(c->reg.R0, 2); |
| |
| /* Shift so that lowest outcode bit is rightmost: |
| */ |
| brw_SHR(p, c->reg.planemask, incoming, brw_imm_ud(26)); |
| |
| if (c->key.nr_userclip) { |
| struct brw_reg tmp = retype(vec1(get_tmp(c)), BRW_REGISTER_TYPE_UD); |
| |
| /* Rearrange userclip outcodes so that they come directly after |
| * the fixed plane bits. |
| */ |
| brw_AND(p, tmp, incoming, brw_imm_ud(0x3f<<14)); |
| brw_SHR(p, tmp, tmp, brw_imm_ud(8)); |
| brw_OR(p, c->reg.planemask, c->reg.planemask, tmp); |
| |
| release_tmp(c, tmp); |
| } |
| } |
| |