1/************************************************************************** 2 * 3 * Copyright 2003 VMware, Inc. 4 * All Rights Reserved. 5 * 6 * Permission is hereby granted, free of charge, to any person obtaining a 7 * copy of this software and associated documentation files (the 8 * "Software"), to deal in the Software without restriction, including 9 * without limitation the rights to use, copy, modify, merge, publish, 10 * distribute, sub license, and/or sell copies of the Software, and to 11 * permit persons to whom the Software is furnished to do so, subject to 12 * the following conditions: 13 * 14 * The above copyright notice and this permission notice (including the 15 * next paragraph) shall be included in all copies or substantial portions 16 * of the Software. 17 * 18 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS 19 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 20 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. 21 * IN NO EVENT SHALL VMWARE AND/OR ITS SUPPLIERS BE LIABLE FOR 22 * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, 23 * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE 24 * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 25 * 26 **************************************************************************/ 27 28#include "i915_batch.h" 29#include "i915_context.h" 30#include "i915_reg.h" 31#include "i915_state.h" 32#include "i915_state_inlines.h" 33 34#include "util/u_memory.h" 35#include "util/u_pack_color.h" 36 37/* State that we have chosen to store in the DYNAMIC segment of the 38 * i915 indirect state mechanism. 39 * 40 * Can't cache these in the way we do the static state, as there is no 41 * start/size in the command packet, instead an 'end' value that gets 42 * incremented. 43 * 44 * Additionally, there seems to be a requirement to re-issue the full 45 * (active) state every time a 4kb boundary is crossed. 46 */ 47 48static inline void 49set_dynamic(struct i915_context *i915, unsigned offset, const unsigned state) 50{ 51 if (i915->current.dynamic[offset] == state) 52 return; 53 54 i915->current.dynamic[offset] = state; 55 i915->dynamic_dirty |= 1 << offset; 56 i915->hardware_dirty |= I915_HW_DYNAMIC; 57} 58 59static inline void 60set_dynamic_array(struct i915_context *i915, unsigned offset, 61 const unsigned *src, unsigned dwords) 62{ 63 unsigned i; 64 65 if (!memcmp(src, &i915->current.dynamic[offset], dwords * 4)) 66 return; 67 68 for (i = 0; i < dwords; i++) { 69 i915->current.dynamic[offset + i] = src[i]; 70 i915->dynamic_dirty |= 1 << (offset + i); 71 } 72 73 i915->hardware_dirty |= I915_HW_DYNAMIC; 74} 75 76/*********************************************************************** 77 * Modes4: stencil masks and logicop 78 */ 79static void 80upload_MODES4(struct i915_context *i915) 81{ 82 bool stencil_ccw = i915_stencil_ccw(i915); 83 84 unsigned modes4 = 0; 85 86 /* I915_NEW_STENCIL 87 */ 88 if (stencil_ccw) 89 modes4 |= i915->depth_stencil->stencil_modes4_ccw; 90 else 91 modes4 |= i915->depth_stencil->stencil_modes4_cw; 92 93 /* I915_NEW_BLEND 94 */ 95 modes4 |= i915->blend->modes4; 96 97 set_dynamic(i915, I915_DYNAMIC_MODES4, modes4); 98} 99 100const struct i915_tracked_state i915_upload_MODES4 = { 101 "MODES4", upload_MODES4, 102 I915_NEW_BLEND | I915_NEW_DEPTH_STENCIL | I915_NEW_RASTERIZER}; 103 104/*********************************************************************** 105 */ 106static void 107upload_BFO(struct i915_context *i915) 108{ 109 bool stencil_ccw = i915_stencil_ccw(i915); 110 111 unsigned bfo[2]; 112 if (stencil_ccw) { 113 bfo[0] = i915->depth_stencil->bfo_ccw[0]; 114 bfo[1] = i915->depth_stencil->bfo_ccw[1]; 115 } else { 116 bfo[0] = i915->depth_stencil->bfo_cw[0]; 117 bfo[1] = i915->depth_stencil->bfo_cw[1]; 118 } 119 /* I don't get it only allowed to set a ref mask when the enable bit is set? 120 */ 121 if (bfo[0] & BFO_ENABLE_STENCIL_REF) { 122 bfo[0] |= i915->stencil_ref.ref_value[!stencil_ccw] 123 << BFO_STENCIL_REF_SHIFT; 124 } 125 126 set_dynamic_array(i915, I915_DYNAMIC_BFO_0, bfo, 2); 127} 128 129const struct i915_tracked_state i915_upload_BFO = { 130 "BFO", upload_BFO, I915_NEW_DEPTH_STENCIL | I915_NEW_RASTERIZER}; 131 132/*********************************************************************** 133 */ 134static void 135upload_BLENDCOLOR(struct i915_context *i915) 136{ 137 unsigned bc[2]; 138 139 memset(bc, 0, sizeof(bc)); 140 141 /* I915_NEW_BLEND 142 */ 143 { 144 const float *color = i915->blend_color.color; 145 146 bc[0] = _3DSTATE_CONST_BLEND_COLOR_CMD; 147 bc[1] = pack_ui32_float4(color[i915->current.color_swizzle[2]], 148 color[i915->current.color_swizzle[1]], 149 color[i915->current.color_swizzle[0]], 150 color[i915->current.color_swizzle[3]]); 151 } 152 153 set_dynamic_array(i915, I915_DYNAMIC_BC_0, bc, 2); 154} 155 156const struct i915_tracked_state i915_upload_BLENDCOLOR = { 157 "BLENDCOLOR", upload_BLENDCOLOR, I915_NEW_BLEND | I915_NEW_COLOR_SWIZZLE}; 158 159/*********************************************************************** 160 */ 161static void 162upload_IAB(struct i915_context *i915) 163{ 164 unsigned iab = 0; 165 166 if (i915->blend) { 167 struct i915_surface *cbuf = i915_surface(i915->framebuffer.cbufs[0]); 168 if (cbuf && cbuf->alpha_in_g) 169 iab |= i915->blend->iab_alpha_in_g; 170 else if (cbuf && cbuf->alpha_is_x) 171 iab |= i915->blend->iab_alpha_is_x; 172 else 173 iab |= i915->blend->iab; 174 } 175 176 set_dynamic(i915, I915_DYNAMIC_IAB, iab); 177} 178 179const struct i915_tracked_state i915_upload_IAB = { 180 "IAB", upload_IAB, I915_NEW_BLEND | I915_NEW_FRAMEBUFFER}; 181 182/*********************************************************************** 183 */ 184static void 185upload_DEPTHSCALE(struct i915_context *i915) 186{ 187 set_dynamic_array(i915, I915_DYNAMIC_DEPTHSCALE_0, 188 &i915->rasterizer->ds[0].u, 2); 189} 190 191const struct i915_tracked_state i915_upload_DEPTHSCALE = { 192 "DEPTHSCALE", upload_DEPTHSCALE, I915_NEW_RASTERIZER}; 193 194/*********************************************************************** 195 * Polygon stipple 196 * 197 * The i915 supports a 4x4 stipple natively, GL wants 32x32. 198 * Fortunately stipple is usually a repeating pattern. 199 * 200 * XXX: does stipple pattern need to be adjusted according to 201 * the window position? 202 * 203 * XXX: possibly need workaround for conform paths test. 204 */ 205static void 206upload_STIPPLE(struct i915_context *i915) 207{ 208 unsigned st[2]; 209 210 st[0] = _3DSTATE_STIPPLE; 211 st[1] = 0; 212 213 /* I915_NEW_RASTERIZER 214 */ 215 if (i915->rasterizer) 216 st[1] |= i915->rasterizer->st; 217 218 /* I915_NEW_STIPPLE 219 */ 220 { 221 const ubyte *mask = (const ubyte *)i915->poly_stipple.stipple; 222 ubyte p[4]; 223 224 p[0] = mask[12] & 0xf; 225 p[1] = mask[8] & 0xf; 226 p[2] = mask[4] & 0xf; 227 p[3] = mask[0] & 0xf; 228 229 /* Not sure what to do about fallbacks, so for now just dont: 230 */ 231 st[1] |= ((p[0] << 0) | (p[1] << 4) | (p[2] << 8) | (p[3] << 12)); 232 } 233 234 set_dynamic_array(i915, I915_DYNAMIC_STP_0, st, 2); 235} 236 237const struct i915_tracked_state i915_upload_STIPPLE = { 238 "STIPPLE", upload_STIPPLE, I915_NEW_RASTERIZER | I915_NEW_STIPPLE}; 239 240/*********************************************************************** 241 * Scissor enable 242 */ 243static void 244upload_SCISSOR_ENABLE(struct i915_context *i915) 245{ 246 set_dynamic(i915, I915_DYNAMIC_SC_ENA_0, i915->rasterizer->sc[0]); 247} 248 249const struct i915_tracked_state i915_upload_SCISSOR_ENABLE = { 250 "SCISSOR ENABLE", upload_SCISSOR_ENABLE, I915_NEW_RASTERIZER}; 251 252/*********************************************************************** 253 * Scissor rect 254 */ 255static void 256upload_SCISSOR_RECT(struct i915_context *i915) 257{ 258 unsigned x1 = i915->scissor.minx; 259 unsigned y1 = i915->scissor.miny; 260 unsigned x2 = i915->scissor.maxx - 1; 261 unsigned y2 = i915->scissor.maxy - 1; 262 unsigned sc[3]; 263 264 sc[0] = _3DSTATE_SCISSOR_RECT_0_CMD; 265 sc[1] = (y1 << 16) | (x1 & 0xffff); 266 sc[2] = (y2 << 16) | (x2 & 0xffff); 267 268 set_dynamic_array(i915, I915_DYNAMIC_SC_RECT_0, sc, 3); 269} 270 271const struct i915_tracked_state i915_upload_SCISSOR_RECT = { 272 "SCISSOR RECT", upload_SCISSOR_RECT, I915_NEW_SCISSOR}; 273 274/*********************************************************************** 275 */ 276static const struct i915_tracked_state *atoms[] = { 277 &i915_upload_MODES4, &i915_upload_BFO, 278 &i915_upload_BLENDCOLOR, &i915_upload_IAB, 279 &i915_upload_DEPTHSCALE, &i915_upload_STIPPLE, 280 &i915_upload_SCISSOR_ENABLE, &i915_upload_SCISSOR_RECT}; 281 282/* These will be dynamic indirect state commands, but for now just end 283 * up on the batch buffer with everything else. 284 */ 285static void 286update_dynamic(struct i915_context *i915) 287{ 288 int i; 289 290 for (i = 0; i < ARRAY_SIZE(atoms); i++) 291 if (i915->dirty & atoms[i]->dirty) 292 atoms[i]->update(i915); 293} 294 295struct i915_tracked_state i915_hw_dynamic = { 296 "dynamic", update_dynamic, 297 ~0 /* all state atoms, because we do internal checking */ 298}; 299