/** * Polygon stipple offset packet */ static void upload_polygon_stipple_offset(struct brw_context *brw) { struct gl_context *ctx = &brw->ctx; /* _NEW_POLYGON */ if (!ctx->Polygon.StippleFlag) return; BEGIN_BATCH(2); OUT_BATCH(_3DSTATE_POLY_STIPPLE_OFFSET << 16 | (2-2)); /* _NEW_BUFFERS * * If we're drawing to a system window we have to invert the Y axis * in order to match the OpenGL pixel coordinate system, and our * offset must be matched to the window position. If we're drawing * to a user-created FBO then our native pixel coordinate system * works just fine, and there's no window system to worry about. */ if (_mesa_is_winsys_fbo(ctx->DrawBuffer)) OUT_BATCH((32 - (_mesa_geometric_height(ctx->DrawBuffer) & 31)) & 31); else OUT_BATCH(0); ADVANCE_BATCH(); }
/** * Scissor depends on the scissor box, and the framebuffer dimensions. */ static void update_scissor( struct st_context *st ) { struct pipe_scissor_state scissor[PIPE_MAX_VIEWPORTS]; const struct gl_context *ctx = st->ctx; const struct gl_framebuffer *fb = ctx->DrawBuffer; const unsigned int fb_width = _mesa_geometric_width(fb); const unsigned int fb_height = _mesa_geometric_height(fb); GLint miny, maxy; unsigned i; bool changed = false; for (i = 0 ; i < ctx->Const.MaxViewports; i++) { scissor[i].minx = 0; scissor[i].miny = 0; scissor[i].maxx = fb_width; scissor[i].maxy = fb_height; if (ctx->Scissor.EnableFlags & (1 << i)) { /* need to be careful here with xmax or ymax < 0 */ GLint xmax = MAX2(0, ctx->Scissor.ScissorArray[i].X + ctx->Scissor.ScissorArray[i].Width); GLint ymax = MAX2(0, ctx->Scissor.ScissorArray[i].Y + ctx->Scissor.ScissorArray[i].Height); if (ctx->Scissor.ScissorArray[i].X > (GLint)scissor[i].minx) scissor[i].minx = ctx->Scissor.ScissorArray[i].X; if (ctx->Scissor.ScissorArray[i].Y > (GLint)scissor[i].miny) scissor[i].miny = ctx->Scissor.ScissorArray[i].Y; if (xmax < (GLint) scissor[i].maxx) scissor[i].maxx = xmax; if (ymax < (GLint) scissor[i].maxy) scissor[i].maxy = ymax; /* check for null space */ if (scissor[i].minx >= scissor[i].maxx || scissor[i].miny >= scissor[i].maxy) scissor[i].minx = scissor[i].miny = scissor[i].maxx = scissor[i].maxy = 0; } /* Now invert Y if needed. * Gallium drivers use the convention Y=0=top for surfaces. */ if (st_fb_orientation(fb) == Y_0_TOP) { miny = fb->Height - scissor[i].maxy; maxy = fb->Height - scissor[i].miny; scissor[i].miny = miny; scissor[i].maxy = maxy; } if (memcmp(&scissor[i], &st->state.scissor[i], sizeof(scissor[0])) != 0) { /* state has changed */ st->state.scissor[i] = scissor[i]; /* struct copy */ changed = true; } } if (changed) st->pipe->set_scissor_states(st->pipe, 0, ctx->Const.MaxViewports, scissor); /* activate */ }
/* Constant single cliprect for framebuffer object or DRI2 drawing */ static void upload_drawing_rect(struct brw_context *brw) { struct gl_context *ctx = &brw->ctx; const struct gl_framebuffer *fb = ctx->DrawBuffer; const unsigned int fb_width = _mesa_geometric_width(fb); const unsigned int fb_height = _mesa_geometric_height(fb); BEGIN_BATCH(4); OUT_BATCH(_3DSTATE_DRAWING_RECTANGLE << 16 | (4 - 2)); OUT_BATCH(0); /* xmin, ymin */ OUT_BATCH(((fb_width - 1) & 0xffff) | ((fb_height - 1) << 16)); OUT_BATCH(0); ADVANCE_BATCH(); }
static void gen6_upload_sf_vp(struct brw_context *brw) { struct gl_context *ctx = &brw->ctx; struct gen6_sf_viewport *sfv; GLfloat y_scale, y_bias; const bool render_to_fbo = _mesa_is_user_fbo(ctx->DrawBuffer); sfv = brw_state_batch(brw, AUB_TRACE_SF_VP_STATE, sizeof(*sfv) * ctx->Const.MaxViewports, 32, &brw->sf.vp_offset); memset(sfv, 0, sizeof(*sfv) * ctx->Const.MaxViewports); /* _NEW_BUFFERS */ if (render_to_fbo) { y_scale = 1.0; y_bias = 0.0; } else { y_scale = -1.0; y_bias = (float)_mesa_geometric_height(ctx->DrawBuffer); } for (unsigned i = 0; i < ctx->Const.MaxViewports; i++) { float scale[3], translate[3]; /* _NEW_VIEWPORT */ _mesa_get_viewport_xform(ctx, i, scale, translate); sfv[i].m00 = scale[0]; sfv[i].m11 = scale[1] * y_scale; sfv[i].m22 = scale[2]; sfv[i].m30 = translate[0]; sfv[i].m31 = translate[1] * y_scale + y_bias; sfv[i].m32 = translate[2]; } brw->ctx.NewDriverState |= BRW_NEW_SF_VP; }
static void gen7_upload_sf_clip_viewport(struct brw_context *brw) { struct gl_context *ctx = &brw->ctx; GLfloat y_scale, y_bias; const bool render_to_fbo = _mesa_is_user_fbo(ctx->DrawBuffer); struct gen7_sf_clip_viewport *vp; /* BRW_NEW_VIEWPORT_COUNT */ const unsigned viewport_count = brw->clip.viewport_count; vp = brw_state_batch(brw, AUB_TRACE_SF_VP_STATE, sizeof(*vp) * viewport_count, 64, &brw->sf.vp_offset); /* Also assign to clip.vp_offset in case something uses it. */ brw->clip.vp_offset = brw->sf.vp_offset; /* _NEW_BUFFERS */ if (render_to_fbo) { y_scale = 1.0; y_bias = 0.0; } else { y_scale = -1.0; y_bias = (float)_mesa_geometric_height(ctx->DrawBuffer); } for (unsigned i = 0; i < viewport_count; i++) { float scale[3], translate[3]; _mesa_get_viewport_xform(ctx, i, scale, translate); /* According to the "Vertex X,Y Clamping and Quantization" section of * the Strips and Fans documentation, objects must not have a * screen-space extents of over 8192 pixels, or they may be * mis-rasterized. The maximum screen space coordinates of a small * object may larger, but we have no way to enforce the object size * other than through clipping. * * If you're surprised that we set clip to -gbx to +gbx and it seems * like we'll end up with 16384 wide, note that for a 8192-wide render * target, we'll end up with a normal (-1, 1) clip volume that just * covers the drawable. */ const float maximum_guardband_extent = 8192; const float gbx = maximum_guardband_extent / ctx->ViewportArray[i].Width; const float gby = maximum_guardband_extent / ctx->ViewportArray[i].Height; vp[i].guardband.xmin = -gbx; vp[i].guardband.xmax = gbx; vp[i].guardband.ymin = -gby; vp[i].guardband.ymax = gby; /* _NEW_VIEWPORT */ vp[i].viewport.m00 = scale[0]; vp[i].viewport.m11 = scale[1] * y_scale; vp[i].viewport.m22 = scale[2]; vp[i].viewport.m30 = translate[0]; vp[i].viewport.m31 = translate[1] * y_scale + y_bias; vp[i].viewport.m32 = translate[2]; } BEGIN_BATCH(2); OUT_BATCH(_3DSTATE_VIEWPORT_STATE_POINTERS_SF_CL << 16 | (2 - 2)); OUT_BATCH(brw->sf.vp_offset); ADVANCE_BATCH(); }
static void brw_wm_populate_key(struct brw_context *brw, struct brw_wm_prog_key *key) { struct gl_context *ctx = &brw->ctx; /* BRW_NEW_FRAGMENT_PROGRAM */ const struct brw_fragment_program *fp = (struct brw_fragment_program *) brw->fragment_program; const struct gl_program *prog = (struct gl_program *) brw->fragment_program; GLuint lookup = 0; GLuint line_aa; bool program_uses_dfdy = fp->program.UsesDFdy; const bool multisample_fbo = _mesa_geometric_samples(ctx->DrawBuffer) > 1; memset(key, 0, sizeof(*key)); /* Build the index for table lookup */ if (brw->gen < 6) { /* _NEW_COLOR */ if (fp->program.UsesKill || ctx->Color.AlphaEnabled) lookup |= IZ_PS_KILL_ALPHATEST_BIT; if (fp->program.Base.OutputsWritten & BITFIELD64_BIT(FRAG_RESULT_DEPTH)) lookup |= IZ_PS_COMPUTES_DEPTH_BIT; /* _NEW_DEPTH */ if (ctx->Depth.Test) lookup |= IZ_DEPTH_TEST_ENABLE_BIT; if (ctx->Depth.Test && ctx->Depth.Mask) /* ?? */ lookup |= IZ_DEPTH_WRITE_ENABLE_BIT; /* _NEW_STENCIL | _NEW_BUFFERS */ if (ctx->Stencil._Enabled) { lookup |= IZ_STENCIL_TEST_ENABLE_BIT; if (ctx->Stencil.WriteMask[0] || ctx->Stencil.WriteMask[ctx->Stencil._BackFace]) lookup |= IZ_STENCIL_WRITE_ENABLE_BIT; } key->iz_lookup = lookup; } line_aa = AA_NEVER; /* _NEW_LINE, _NEW_POLYGON, BRW_NEW_REDUCED_PRIMITIVE */ if (ctx->Line.SmoothFlag) { if (brw->reduced_primitive == GL_LINES) { line_aa = AA_ALWAYS; } else if (brw->reduced_primitive == GL_TRIANGLES) { if (ctx->Polygon.FrontMode == GL_LINE) { line_aa = AA_SOMETIMES; if (ctx->Polygon.BackMode == GL_LINE || (ctx->Polygon.CullFlag && ctx->Polygon.CullFaceMode == GL_BACK)) line_aa = AA_ALWAYS; } else if (ctx->Polygon.BackMode == GL_LINE) { line_aa = AA_SOMETIMES; if ((ctx->Polygon.CullFlag && ctx->Polygon.CullFaceMode == GL_FRONT)) line_aa = AA_ALWAYS; } } } key->line_aa = line_aa; /* _NEW_HINT */ key->high_quality_derivatives = ctx->Hint.FragmentShaderDerivative == GL_NICEST; if (brw->gen < 6) key->stats_wm = brw->stats_wm; /* _NEW_LIGHT */ key->flat_shade = (ctx->Light.ShadeModel == GL_FLAT); /* _NEW_FRAG_CLAMP | _NEW_BUFFERS */ key->clamp_fragment_color = ctx->Color._ClampFragmentColor; /* _NEW_TEXTURE */ brw_populate_sampler_prog_key_data(ctx, prog, brw->wm.base.sampler_count, &key->tex); /* _NEW_BUFFERS */ /* * Include the draw buffer origin and height so that we can calculate * fragment position values relative to the bottom left of the drawable, * from the incoming screen origin relative position we get as part of our * payload. * * This is only needed for the WM_WPOSXY opcode when the fragment program * uses the gl_FragCoord input. * * We could avoid recompiling by including this as a constant referenced by * our program, but if we were to do that it would also be nice to handle * getting that constant updated at batchbuffer submit time (when we * hold the lock and know where the buffer really is) rather than at emit * time when we don't hold the lock and are just guessing. We could also * just avoid using this as key data if the program doesn't use * fragment.position. * * For DRI2 the origin_x/y will always be (0,0) but we still need the * drawable height in order to invert the Y axis. */ if (fp->program.Base.InputsRead & VARYING_BIT_POS) { key->drawable_height = _mesa_geometric_height(ctx->DrawBuffer); } if ((fp->program.Base.InputsRead & VARYING_BIT_POS) || program_uses_dfdy) { key->render_to_fbo = _mesa_is_user_fbo(ctx->DrawBuffer); } /* _NEW_BUFFERS */ key->nr_color_regions = ctx->DrawBuffer->_NumColorDrawBuffers; /* _NEW_MULTISAMPLE, _NEW_COLOR, _NEW_BUFFERS */ key->replicate_alpha = ctx->DrawBuffer->_NumColorDrawBuffers > 1 && (ctx->Multisample.SampleAlphaToCoverage || ctx->Color.AlphaEnabled); /* _NEW_BUFFERS _NEW_MULTISAMPLE */ /* Ignore sample qualifier while computing this flag. */ key->persample_shading = _mesa_get_min_invocations_per_fragment(ctx, &fp->program, true) > 1; if (key->persample_shading) key->persample_2x = _mesa_geometric_samples(ctx->DrawBuffer) == 2; key->compute_pos_offset = _mesa_get_min_invocations_per_fragment(ctx, &fp->program, false) > 1 && fp->program.Base.SystemValuesRead & SYSTEM_BIT_SAMPLE_POS; key->compute_sample_id = multisample_fbo && ctx->Multisample.Enabled && (fp->program.Base.SystemValuesRead & SYSTEM_BIT_SAMPLE_ID); /* BRW_NEW_VUE_MAP_GEOM_OUT */ if (brw->gen < 6 || _mesa_bitcount_64(fp->program.Base.InputsRead & BRW_FS_VARYING_INPUT_MASK) > 16) key->input_slots_valid = brw->vue_map_geom_out.slots_valid; /* _NEW_COLOR | _NEW_BUFFERS */ /* Pre-gen6, the hardware alpha test always used each render * target's alpha to do alpha test, as opposed to render target 0's alpha * like GL requires. Fix that by building the alpha test into the * shader, and we'll skip enabling the fixed function alpha test. */ if (brw->gen < 6 && ctx->DrawBuffer->_NumColorDrawBuffers > 1 && ctx->Color.AlphaEnabled) { key->alpha_test_func = ctx->Color.AlphaFunc; key->alpha_test_ref = ctx->Color.AlphaRef; } /* The unique fragment program ID */ key->program_string_id = fp->id; }
static void upload_clip_state(struct brw_context *brw) { struct gl_context *ctx = &brw->ctx; /* BRW_NEW_META_IN_PROGRESS */ uint32_t dw1 = brw->meta_in_progress ? 0 : GEN6_CLIP_STATISTICS_ENABLE; uint32_t dw2 = 0; /* _NEW_BUFFERS */ struct gl_framebuffer *fb = ctx->DrawBuffer; /* BRW_NEW_FS_PROG_DATA */ if (brw->wm.prog_data->barycentric_interp_modes & BRW_WM_NONPERSPECTIVE_BARYCENTRIC_BITS) { dw2 |= GEN6_CLIP_NON_PERSPECTIVE_BARYCENTRIC_ENABLE; } dw1 |= brw->vs.prog_data->base.cull_distance_mask; if (brw->gen >= 7) dw1 |= GEN7_CLIP_EARLY_CULL; if (brw->gen == 7) { /* _NEW_POLYGON */ if (ctx->Polygon._FrontBit == _mesa_is_user_fbo(fb)) dw1 |= GEN7_CLIP_WINDING_CCW; if (ctx->Polygon.CullFlag) { switch (ctx->Polygon.CullFaceMode) { case GL_FRONT: dw1 |= GEN7_CLIP_CULLMODE_FRONT; break; case GL_BACK: dw1 |= GEN7_CLIP_CULLMODE_BACK; break; case GL_FRONT_AND_BACK: dw1 |= GEN7_CLIP_CULLMODE_BOTH; break; default: unreachable("Should not get here: invalid CullFlag"); } } else { dw1 |= GEN7_CLIP_CULLMODE_NONE; } } if (brw->gen < 8 && !ctx->Transform.DepthClamp) dw2 |= GEN6_CLIP_Z_TEST; /* _NEW_LIGHT */ if (ctx->Light.ProvokingVertex == GL_FIRST_VERTEX_CONVENTION) { dw2 |= (0 << GEN6_CLIP_TRI_PROVOKE_SHIFT) | (1 << GEN6_CLIP_TRIFAN_PROVOKE_SHIFT) | (0 << GEN6_CLIP_LINE_PROVOKE_SHIFT); } else { dw2 |= (2 << GEN6_CLIP_TRI_PROVOKE_SHIFT) | (2 << GEN6_CLIP_TRIFAN_PROVOKE_SHIFT) | (1 << GEN6_CLIP_LINE_PROVOKE_SHIFT); } /* _NEW_TRANSFORM */ dw2 |= (ctx->Transform.ClipPlanesEnabled << GEN6_USER_CLIP_CLIP_DISTANCES_SHIFT); if (ctx->Transform.ClipDepthMode == GL_ZERO_TO_ONE) dw2 |= GEN6_CLIP_API_D3D; else dw2 |= GEN6_CLIP_API_OGL; dw2 |= GEN6_CLIP_GB_TEST; /* We need to disable guardband clipping if the guardband (which we always * program to the maximum screen-space bounding box of 8K x 8K) will be * smaller than the viewport. * * Closely examining the clip determination formulas in the documentation * reveals that objects will be discarded entirely if they're outside the * (small) guardband, even if they're within the (large) viewport: * * TR = TR_GB || TR_VPXY || TR_VPZ || TR_UC || TR_NEGW * TA = !TR && TA_GB && TA_VPZ && TA_NEGW * MC = !(TA || TR) * * (TA is "Trivial Accept", TR is "Trivial Reject", MC is "Must Clip".) * * Disabling guardband clipping removes the TR_GB condition, which means * they'll be considered MC ("Must Clip") unless they're rejected for * some other reason. * * Note that there is no TA_VPXY condition. If there were, objects entirely * inside a 16384x16384 viewport would be trivially accepted, breaking the * "objects must have a screenspace bounding box not exceeding 8K in the X * or Y direction" restriction. Instead, they're clipped. */ for (unsigned i = 0; i < ctx->Const.MaxViewports; i++) { if (ctx->ViewportArray[i].Width > 8192 || ctx->ViewportArray[i].Height > 8192) { dw2 &= ~GEN6_CLIP_GB_TEST; break; } } /* If the viewport dimensions are smaller than the drawable dimensions, * we have to disable guardband clipping prior to Gen8. We always program * the guardband to a fixed size, which is almost always larger than the * viewport. Any geometry which intersects the viewport but lies within * the guardband would bypass the 3D clipping stage, so it wouldn't be * clipped to the viewport. Rendering would happen beyond the viewport, * but still inside the drawable. * * Gen8+ introduces a viewport extents test which restricts rendering to * the viewport, so we can ignore this restriction. */ if (brw->gen < 8) { const float fb_width = (float)_mesa_geometric_width(fb); const float fb_height = (float)_mesa_geometric_height(fb); for (unsigned i = 0; i < ctx->Const.MaxViewports; i++) { if (ctx->ViewportArray[i].X != 0 || ctx->ViewportArray[i].Y != 0 || ctx->ViewportArray[i].Width != fb_width || ctx->ViewportArray[i].Height != fb_height) { dw2 &= ~GEN6_CLIP_GB_TEST; break; } } } /* BRW_NEW_RASTERIZER_DISCARD */ if (ctx->RasterDiscard) { dw2 |= GEN6_CLIP_MODE_REJECT_ALL; if (brw->gen == 6) { perf_debug("Rasterizer discard is currently implemented via the " "clipper; having the GS not write primitives would " "likely be faster.\n"); } } uint32_t enable; if (brw->primitive == _3DPRIM_RECTLIST) enable = 0; else enable = GEN6_CLIP_ENABLE; if (!is_drawing_points(brw) && !is_drawing_lines(brw)) dw2 |= GEN6_CLIP_XY_TEST; /* BRW_NEW_VUE_MAP_GEOM_OUT */ const int max_vp_index = (brw->vue_map_geom_out.slots_valid & VARYING_BIT_VIEWPORT) != 0 ? ctx->Const.MaxViewports : 1; BEGIN_BATCH(4); OUT_BATCH(_3DSTATE_CLIP << 16 | (4 - 2)); OUT_BATCH(dw1); OUT_BATCH(enable | GEN6_CLIP_MODE_NORMAL | dw2); OUT_BATCH(U_FIXED(0.125, 3) << GEN6_CLIP_MIN_POINT_WIDTH_SHIFT | U_FIXED(255.875, 3) << GEN6_CLIP_MAX_POINT_WIDTH_SHIFT | (_mesa_geometric_layers(fb) > 0 ? 0 : GEN6_CLIP_FORCE_ZERO_RTAINDEX) | ((max_vp_index - 1) & GEN6_CLIP_MAX_VP_INDEX_MASK)); ADVANCE_BATCH(); }
/** * Update framebuffer state (color, depth, stencil, etc. buffers) */ void st_update_framebuffer_state( struct st_context *st ) { struct pipe_framebuffer_state framebuffer; struct gl_framebuffer *fb = st->ctx->DrawBuffer; struct st_renderbuffer *strb; GLuint i; st_flush_bitmap_cache(st); st_invalidate_readpix_cache(st); st->state.fb_orientation = st_fb_orientation(fb); /** * Quantize the derived default number of samples: * * A query to the driver of supported MSAA values the * hardware supports is done as to legalize the number * of application requested samples, NumSamples. * See commit eb9cf3c for more information. */ fb->DefaultGeometry._NumSamples = framebuffer_quantize_num_samples(st, fb->DefaultGeometry.NumSamples); framebuffer.width = _mesa_geometric_width(fb); framebuffer.height = _mesa_geometric_height(fb); framebuffer.samples = _mesa_geometric_samples(fb); framebuffer.layers = _mesa_geometric_layers(fb); /* Examine Mesa's ctx->DrawBuffer->_ColorDrawBuffers state * to determine which surfaces to draw to */ framebuffer.nr_cbufs = fb->_NumColorDrawBuffers; for (i = 0; i < fb->_NumColorDrawBuffers; i++) { framebuffer.cbufs[i] = NULL; strb = st_renderbuffer(fb->_ColorDrawBuffers[i]); if (strb) { if (strb->is_rtt || (strb->texture && _mesa_get_format_color_encoding(strb->Base.Format) == GL_SRGB)) { /* rendering to a GL texture, may have to update surface */ st_update_renderbuffer_surface(st, strb); } if (strb->surface) { framebuffer.cbufs[i] = strb->surface; update_framebuffer_size(&framebuffer, strb->surface); } strb->defined = GL_TRUE; /* we'll be drawing something */ } } for (i = framebuffer.nr_cbufs; i < PIPE_MAX_COLOR_BUFS; i++) { framebuffer.cbufs[i] = NULL; } /* Remove trailing GL_NONE draw buffers. */ while (framebuffer.nr_cbufs && !framebuffer.cbufs[framebuffer.nr_cbufs-1]) { framebuffer.nr_cbufs--; } /* * Depth/Stencil renderbuffer/surface. */ strb = st_renderbuffer(fb->Attachment[BUFFER_DEPTH].Renderbuffer); if (!strb) strb = st_renderbuffer(fb->Attachment[BUFFER_STENCIL].Renderbuffer); if (strb) { if (strb->is_rtt) { /* rendering to a GL texture, may have to update surface */ st_update_renderbuffer_surface(st, strb); } framebuffer.zsbuf = strb->surface; update_framebuffer_size(&framebuffer, strb->surface); } else framebuffer.zsbuf = NULL; #ifdef DEBUG /* Make sure the resource binding flags were set properly */ for (i = 0; i < framebuffer.nr_cbufs; i++) { assert(!framebuffer.cbufs[i] || framebuffer.cbufs[i]->texture->bind & PIPE_BIND_RENDER_TARGET); } if (framebuffer.zsbuf) { assert(framebuffer.zsbuf->texture->bind & PIPE_BIND_DEPTH_STENCIL); } #endif if (framebuffer.width == USHRT_MAX) framebuffer.width = 0; if (framebuffer.height == USHRT_MAX) framebuffer.height = 0; cso_set_framebuffer(st->cso_context, &framebuffer); st->state.fb_width = framebuffer.width; st->state.fb_height = framebuffer.height; st->state.fb_num_samples = util_framebuffer_get_num_samples(&framebuffer); st->state.fb_num_layers = util_framebuffer_get_num_layers(&framebuffer); st->state.fb_num_cb = framebuffer.nr_cbufs; }
static void st_DrawTex(struct gl_context *ctx, GLfloat x, GLfloat y, GLfloat z, GLfloat width, GLfloat height) { struct st_context *st = ctx->st; struct pipe_context *pipe = st->pipe; struct cso_context *cso = st->cso_context; struct pipe_resource *vbuffer = NULL; GLuint i, numTexCoords, numAttribs; GLboolean emitColor; uint semantic_names[2 + MAX_TEXTURE_UNITS]; uint semantic_indexes[2 + MAX_TEXTURE_UNITS]; struct pipe_vertex_element velements[2 + MAX_TEXTURE_UNITS]; unsigned offset; st_flush_bitmap_cache(st); st_invalidate_readpix_cache(st); st_validate_state(st, ST_PIPELINE_RENDER); /* determine if we need vertex color */ if (ctx->FragmentProgram._Current->info.inputs_read & VARYING_BIT_COL0) emitColor = GL_TRUE; else emitColor = GL_FALSE; /* determine how many enabled sets of texcoords */ numTexCoords = 0; for (i = 0; i < ctx->Const.MaxTextureUnits; i++) { if (ctx->Texture.Unit[i]._Current && ctx->Texture.Unit[i]._Current->Target == GL_TEXTURE_2D) { numTexCoords++; } } /* total number of attributes per vertex */ numAttribs = 1 + emitColor + numTexCoords; /* load vertex buffer */ { #define SET_ATTRIB(VERT, ATTR, X, Y, Z, W) \ do { \ GLuint k = (((VERT) * numAttribs + (ATTR)) * 4); \ assert(k < 4 * 4 * numAttribs); \ vbuf[k + 0] = X; \ vbuf[k + 1] = Y; \ vbuf[k + 2] = Z; \ vbuf[k + 3] = W; \ } while (0) const GLfloat x0 = x, y0 = y, x1 = x + width, y1 = y + height; GLfloat *vbuf = NULL; GLuint tex_attr; u_upload_alloc(pipe->stream_uploader, 0, numAttribs * 4 * 4 * sizeof(GLfloat), 4, &offset, &vbuffer, (void **) &vbuf); if (!vbuffer) { return; } z = CLAMP(z, 0.0f, 1.0f); /* positions (in clip coords) */ { const struct gl_framebuffer *fb = ctx->DrawBuffer; const GLfloat fb_width = (GLfloat)_mesa_geometric_width(fb); const GLfloat fb_height = (GLfloat)_mesa_geometric_height(fb); const GLfloat clip_x0 = (GLfloat)(x0 / fb_width * 2.0 - 1.0); const GLfloat clip_y0 = (GLfloat)(y0 / fb_height * 2.0 - 1.0); const GLfloat clip_x1 = (GLfloat)(x1 / fb_width * 2.0 - 1.0); const GLfloat clip_y1 = (GLfloat)(y1 / fb_height * 2.0 - 1.0); SET_ATTRIB(0, 0, clip_x0, clip_y0, z, 1.0f); /* lower left */ SET_ATTRIB(1, 0, clip_x1, clip_y0, z, 1.0f); /* lower right */ SET_ATTRIB(2, 0, clip_x1, clip_y1, z, 1.0f); /* upper right */ SET_ATTRIB(3, 0, clip_x0, clip_y1, z, 1.0f); /* upper left */ semantic_names[0] = TGSI_SEMANTIC_POSITION; semantic_indexes[0] = 0; } /* colors */ if (emitColor) { const GLfloat *c = ctx->Current.Attrib[VERT_ATTRIB_COLOR0]; SET_ATTRIB(0, 1, c[0], c[1], c[2], c[3]); SET_ATTRIB(1, 1, c[0], c[1], c[2], c[3]); SET_ATTRIB(2, 1, c[0], c[1], c[2], c[3]); SET_ATTRIB(3, 1, c[0], c[1], c[2], c[3]); semantic_names[1] = TGSI_SEMANTIC_COLOR; semantic_indexes[1] = 0; tex_attr = 2; } else { tex_attr = 1; } /* texcoords */ for (i = 0; i < ctx->Const.MaxTextureUnits; i++) { if (ctx->Texture.Unit[i]._Current && ctx->Texture.Unit[i]._Current->Target == GL_TEXTURE_2D) { struct gl_texture_object *obj = ctx->Texture.Unit[i]._Current; const struct gl_texture_image *img = _mesa_base_tex_image(obj); const GLfloat wt = (GLfloat) img->Width; const GLfloat ht = (GLfloat) img->Height; const GLfloat s0 = obj->CropRect[0] / wt; const GLfloat t0 = obj->CropRect[1] / ht; const GLfloat s1 = (obj->CropRect[0] + obj->CropRect[2]) / wt; const GLfloat t1 = (obj->CropRect[1] + obj->CropRect[3]) / ht; /*printf("crop texcoords: %g, %g .. %g, %g\n", s0, t0, s1, t1);*/ SET_ATTRIB(0, tex_attr, s0, t0, 0.0f, 1.0f); /* lower left */ SET_ATTRIB(1, tex_attr, s1, t0, 0.0f, 1.0f); /* lower right */ SET_ATTRIB(2, tex_attr, s1, t1, 0.0f, 1.0f); /* upper right */ SET_ATTRIB(3, tex_attr, s0, t1, 0.0f, 1.0f); /* upper left */ semantic_names[tex_attr] = st->needs_texcoord_semantic ? TGSI_SEMANTIC_TEXCOORD : TGSI_SEMANTIC_GENERIC; /* XXX: should this use semantic index i instead of 0 ? */ semantic_indexes[tex_attr] = 0; tex_attr++; } } u_upload_unmap(pipe->stream_uploader); #undef SET_ATTRIB } cso_save_state(cso, (CSO_BIT_VIEWPORT | CSO_BIT_STREAM_OUTPUTS | CSO_BIT_VERTEX_SHADER | CSO_BIT_TESSCTRL_SHADER | CSO_BIT_TESSEVAL_SHADER | CSO_BIT_GEOMETRY_SHADER | CSO_BIT_VERTEX_ELEMENTS | CSO_BIT_AUX_VERTEX_BUFFER_SLOT)); { void *vs = lookup_shader(pipe, numAttribs, semantic_names, semantic_indexes); cso_set_vertex_shader_handle(cso, vs); } cso_set_tessctrl_shader_handle(cso, NULL); cso_set_tesseval_shader_handle(cso, NULL); cso_set_geometry_shader_handle(cso, NULL); for (i = 0; i < numAttribs; i++) { velements[i].src_offset = i * 4 * sizeof(float); velements[i].instance_divisor = 0; velements[i].vertex_buffer_index = 0; velements[i].src_format = PIPE_FORMAT_R32G32B32A32_FLOAT; } cso_set_vertex_elements(cso, numAttribs, velements); cso_set_stream_outputs(cso, 0, NULL, NULL); /* viewport state: viewport matching window dims */ { const struct gl_framebuffer *fb = ctx->DrawBuffer; const GLboolean invert = (st_fb_orientation(fb) == Y_0_TOP); const GLfloat width = (GLfloat)_mesa_geometric_width(fb); const GLfloat height = (GLfloat)_mesa_geometric_height(fb); struct pipe_viewport_state vp; vp.scale[0] = 0.5f * width; vp.scale[1] = height * (invert ? -0.5f : 0.5f); vp.scale[2] = 1.0f; vp.translate[0] = 0.5f * width; vp.translate[1] = 0.5f * height; vp.translate[2] = 0.0f; cso_set_viewport(cso, &vp); } util_draw_vertex_buffer(pipe, cso, vbuffer, cso_get_aux_vertex_buffer_slot(cso), offset, /* offset */ PIPE_PRIM_TRIANGLE_FAN, 4, /* verts */ numAttribs); /* attribs/vert */ pipe_resource_reference(&vbuffer, NULL); /* restore state */ cso_restore_state(cso); }
static void brw_upload_clip_unit(struct brw_context *brw) { struct gl_context *ctx = &brw->ctx; struct brw_clip_unit_state *clip; /* _NEW_BUFFERS */ const struct gl_framebuffer *fb = ctx->DrawBuffer; const float fb_width = (float)_mesa_geometric_width(fb); const float fb_height = (float)_mesa_geometric_height(fb); upload_clip_vp(brw); clip = brw_state_batch(brw, AUB_TRACE_CLIP_STATE, sizeof(*clip), 32, &brw->clip.state_offset); memset(clip, 0, sizeof(*clip)); /* BRW_NEW_PROGRAM_CACHE | BRW_NEW_CLIP_PROG_DATA */ clip->thread0.grf_reg_count = (ALIGN(brw->clip.prog_data->total_grf, 16) / 16 - 1); clip->thread0.kernel_start_pointer = brw_program_reloc(brw, brw->clip.state_offset + offsetof(struct brw_clip_unit_state, thread0), brw->clip.prog_offset + (clip->thread0.grf_reg_count << 1)) >> 6; clip->thread1.floating_point_mode = BRW_FLOATING_POINT_NON_IEEE_754; clip->thread1.single_program_flow = 1; clip->thread3.urb_entry_read_length = brw->clip.prog_data->urb_read_length; clip->thread3.const_urb_entry_read_length = brw->clip.prog_data->curb_read_length; /* BRW_NEW_CURBE_OFFSETS */ clip->thread3.const_urb_entry_read_offset = brw->curbe.clip_start * 2; clip->thread3.dispatch_grf_start_reg = 1; clip->thread3.urb_entry_read_offset = 0; /* BRW_NEW_URB_FENCE */ clip->thread4.nr_urb_entries = brw->urb.nr_clip_entries; clip->thread4.urb_entry_allocation_size = brw->urb.vsize - 1; /* If we have enough clip URB entries to run two threads, do so. */ if (brw->urb.nr_clip_entries >= 10) { /* Half of the URB entries go to each thread, and it has to be an * even number. */ assert(brw->urb.nr_clip_entries % 2 == 0); /* Although up to 16 concurrent Clip threads are allowed on Ironlake, * only 2 threads can output VUEs at a time. */ if (brw->gen == 5) clip->thread4.max_threads = 16 - 1; else clip->thread4.max_threads = 2 - 1; } else { assert(brw->urb.nr_clip_entries >= 5); clip->thread4.max_threads = 1 - 1; } if (unlikely(INTEL_DEBUG & DEBUG_STATS)) clip->thread4.stats_enable = 1; /* _NEW_TRANSFORM */ if (brw->gen == 5 || brw->is_g4x) clip->clip5.userclip_enable_flags = ctx->Transform.ClipPlanesEnabled; else /* Up to 6 actual clip flags, plus the 7th for negative RHW workaround. */ clip->clip5.userclip_enable_flags = (ctx->Transform.ClipPlanesEnabled & 0x3f) | 0x40; clip->clip5.userclip_must_clip = 1; /* enable guardband clipping if we can */ if (ctx->ViewportArray[0].X == 0 && ctx->ViewportArray[0].Y == 0 && ctx->ViewportArray[0].Width == fb_width && ctx->ViewportArray[0].Height == fb_height) { clip->clip5.guard_band_enable = 1; clip->clip6.clipper_viewport_state_ptr = (brw->batch.bo->offset64 + brw->clip.vp_offset) >> 5; /* emit clip viewport relocation */ drm_intel_bo_emit_reloc(brw->batch.bo, (brw->clip.state_offset + offsetof(struct brw_clip_unit_state, clip6)), brw->batch.bo, brw->clip.vp_offset, I915_GEM_DOMAIN_INSTRUCTION, 0); }