void draw_aapoint_prepare_outputs(struct draw_context *draw, struct draw_stage *stage) { struct aapoint_stage *aapoint = aapoint_stage(stage); const struct pipe_rasterizer_state *rast = draw->rasterizer; /* update vertex attrib info */ aapoint->pos_slot = draw_current_shader_position_output(draw); if (!rast->point_smooth) return; /* allocate the extra post-transformed vertex attribute */ aapoint->tex_slot = draw_alloc_extra_vertex_attrib(draw, TGSI_SEMANTIC_GENERIC, aapoint->fs->generic_attrib); assert(aapoint->tex_slot > 0); /* output[0] is vertex pos */ /* find psize slot in post-transform vertex */ aapoint->psize_slot = -1; if (draw->rasterizer->point_size_per_vertex) { const struct tgsi_shader_info *info = draw_get_shader_info(draw); uint i; /* find PSIZ vertex output */ for (i = 0; i < info->num_outputs; i++) { if (info->output_semantic_name[i] == TGSI_SEMANTIC_PSIZE) { aapoint->psize_slot = i; break; } } } }
void draw_pt_so_emit_prepare(struct pt_so_emit *emit, boolean use_pre_clip_pos) { struct draw_context *draw = emit->draw; emit->use_pre_clip_pos = use_pre_clip_pos; emit->has_so = draw_has_so(draw); if (use_pre_clip_pos) emit->pos_idx = draw_current_shader_position_output(draw); /* if we have a state with outputs make sure we have * buffers to output to */ if (emit->has_so) { boolean has_valid_buffer = FALSE; unsigned i; for (i = 0; i < draw->so.num_targets; ++i) { if (draw->so.targets[i]) { has_valid_buffer = TRUE; break; } } emit->has_so = has_valid_buffer; } if (!emit->has_so) return; /* XXX: need to flush to get prim_vbuf.c to release its allocation?? */ draw_do_flush( draw, DRAW_FLUSH_BACKEND ); }
static void stipple_line(struct draw_stage *stage, struct prim_header *header) { struct stipple_stage *stipple = stipple_stage(stage); struct vertex_header *v0 = header->v[0]; struct vertex_header *v1 = header->v[1]; const unsigned pos = draw_current_shader_position_output(stage->draw); const float *pos0 = v0->data[pos]; const float *pos1 = v1->data[pos]; float start = 0; bool state = 0; float x0 = pos0[0]; float x1 = pos1[0]; float y0 = pos0[1]; float y1 = pos1[1]; float length; int i; if (stipple->smooth) { float dx = x1 - x0; float dy = y1 - y0; length = sqrtf(dx*dx + dy*dy); } else { float dx = x0 > x1 ? x0 - x1 : x1 - x0; float dy = y0 > y1 ? y0 - y1 : y1 - y0; length = MAX2(dx, dy); } if (header->flags & DRAW_PIPE_RESET_STIPPLE) stipple->counter = 0; /* XXX ToDo: instead of iterating pixel-by-pixel, use a look-up table. */ for (i = 0; i < length; i++) { bool result = stipple_test((int)stipple->counter + i, (ushort)stipple->pattern, stipple->factor); if (result != state) { /* changing from "off" to "on" or vice versa */ if (state) { if (start != i) { /* finishing an "on" segment */ emit_segment(stage, header, start / length, i / length); } } else { /* starting an "on" segment */ start = (float)i; } state = result; } } if (state && start < length) emit_segment(stage, header, start / length, 1.0); stipple->counter += length; }
static void aapoint_first_point(struct draw_stage *stage, struct prim_header *header) { auto struct aapoint_stage *aapoint = aapoint_stage(stage); struct draw_context *draw = stage->draw; struct pipe_context *pipe = draw->pipe; const struct pipe_rasterizer_state *rast = draw->rasterizer; void *r; assert(draw->rasterizer->point_smooth); if (draw->rasterizer->point_size <= 2.0) aapoint->radius = 1.0; else aapoint->radius = 0.5f * draw->rasterizer->point_size; /* * Bind (generate) our fragprog. */ bind_aapoint_fragment_shader(aapoint); /* update vertex attrib info */ aapoint->tex_slot = draw_current_shader_outputs(draw); assert(aapoint->tex_slot > 0); /* output[0] is vertex pos */ aapoint->pos_slot = draw_current_shader_position_output(draw); draw->extra_shader_outputs.semantic_name = TGSI_SEMANTIC_GENERIC; draw->extra_shader_outputs.semantic_index = aapoint->fs->generic_attrib; draw->extra_shader_outputs.slot = aapoint->tex_slot; /* find psize slot in post-transform vertex */ aapoint->psize_slot = -1; if (draw->rasterizer->point_size_per_vertex) { /* find PSIZ vertex output */ const struct draw_vertex_shader *vs = draw->vs.vertex_shader; uint i; for (i = 0; i < vs->info.num_outputs; i++) { if (vs->info.output_semantic_name[i] == TGSI_SEMANTIC_PSIZE) { aapoint->psize_slot = i; break; } } } draw->suspend_flushing = TRUE; /* Disable triangle culling, stippling, unfilled mode etc. */ r = draw_get_rasterizer_no_cull(draw, rast->scissor, rast->flatshade); pipe->bind_rasterizer_state(pipe, r); draw->suspend_flushing = FALSE; /* now really draw first point */ stage->point = aapoint_point; stage->point(stage, header); }
static void aaline_first_line(struct draw_stage *stage, struct prim_header *header) { auto struct aaline_stage *aaline = aaline_stage(stage); struct draw_context *draw = stage->draw; struct pipe_context *pipe = draw->pipe; const struct pipe_rasterizer_state *rast = draw->rasterizer; uint num_samplers; void *r; assert(draw->rasterizer->line_smooth); if (draw->rasterizer->line_width <= 2.2) aaline->half_line_width = 1.1f; else aaline->half_line_width = 0.5f * draw->rasterizer->line_width; /* * Bind (generate) our fragprog, sampler and texture */ if (!bind_aaline_fragment_shader(aaline)) { stage->line = draw_pipe_passthrough_line; stage->line(stage, header); return; } /* update vertex attrib info */ aaline->tex_slot = draw_current_shader_outputs(draw); aaline->pos_slot = draw_current_shader_position_output(draw);; /* allocate the extra post-transformed vertex attribute */ (void) draw_alloc_extra_vertex_attrib(draw, TGSI_SEMANTIC_GENERIC, aaline->fs->generic_attrib); /* how many samplers? */ /* we'll use sampler/texture[pstip->sampler_unit] for the stipple */ num_samplers = MAX2(aaline->num_sampler_views, aaline->num_samplers); num_samplers = MAX2(num_samplers, aaline->fs->sampler_unit + 1); aaline->state.sampler[aaline->fs->sampler_unit] = aaline->sampler_cso; pipe_sampler_view_reference(&aaline->state.sampler_views[aaline->fs->sampler_unit], aaline->sampler_view); draw->suspend_flushing = TRUE; aaline->driver_bind_sampler_states(pipe, num_samplers, aaline->state.sampler); aaline->driver_set_sampler_views(pipe, num_samplers, aaline->state.sampler_views); /* Disable triangle culling, stippling, unfilled mode etc. */ r = draw_get_rasterizer_no_cull(draw, rast->scissor, rast->flatshade); pipe->bind_rasterizer_state(pipe, r); draw->suspend_flushing = FALSE; /* now really draw first line */ stage->line = aaline_line; stage->line(stage, header); }
/** * Checks whether the specifed triangle is empty and if it is returns * true, otherwise returns false. * Triangle is considered null/empty if it's area is qual to zero. */ static inline boolean is_tri_null(struct draw_context *draw, const struct prim_header *header) { const unsigned pos_attr = draw_current_shader_position_output(draw); float x1 = header->v[1]->data[pos_attr][0] - header->v[0]->data[pos_attr][0]; float y1 = header->v[1]->data[pos_attr][1] - header->v[0]->data[pos_attr][1]; float z1 = header->v[1]->data[pos_attr][2] - header->v[0]->data[pos_attr][2]; float x2 = header->v[2]->data[pos_attr][0] - header->v[0]->data[pos_attr][0]; float y2 = header->v[2]->data[pos_attr][1] - header->v[0]->data[pos_attr][1]; float z2 = header->v[2]->data[pos_attr][2] - header->v[0]->data[pos_attr][2]; float vx = y1 * z2 - z1 * y2; float vy = x1 * z2 - z1 * x2; float vz = x1 * y2 - y1 * x2; return (vx*vx + vy*vy + vz*vz) == 0.f; }
void draw_aaline_prepare_outputs(struct draw_context *draw, struct draw_stage *stage) { struct aaline_stage *aaline = aaline_stage(stage); const struct pipe_rasterizer_state *rast = draw->rasterizer; /* update vertex attrib info */ aaline->pos_slot = draw_current_shader_position_output(draw);; if (!rast->line_smooth) return; /* allocate the extra post-transformed vertex attribute */ aaline->tex_slot = draw_alloc_extra_vertex_attrib(draw, TGSI_SEMANTIC_GENERIC, aaline->fs->generic_attrib); }
/** * Offset tri Z. Some hardware can handle this, but not usually when * doing unfilled rendering. */ static void do_offset_tri( struct draw_stage *stage, struct prim_header *header ) { const unsigned pos = draw_current_shader_position_output(stage->draw); struct offset_stage *offset = offset_stage(stage); float inv_det = 1.0f / header->det; /* Window coords: */ float *v0 = header->v[0]->data[pos]; float *v1 = header->v[1]->data[pos]; float *v2 = header->v[2]->data[pos]; /* edge vectors e = v0 - v2, f = v1 - v2 */ float ex = v0[0] - v2[0]; float ey = v0[1] - v2[1]; float ez = v0[2] - v2[2]; float fx = v1[0] - v2[0]; float fy = v1[1] - v2[1]; float fz = v1[2] - v2[2]; /* (a,b) = cross(e,f).xy */ float a = ey*fz - ez*fy; float b = ez*fx - ex*fz; float dzdx = fabsf(a * inv_det); float dzdy = fabsf(b * inv_det); float zoffset = offset->units + MAX2(dzdx, dzdy) * offset->scale; if (offset->clamp) zoffset = (offset->clamp < 0.0f) ? MAX2(zoffset, offset->clamp) : MIN2(zoffset, offset->clamp); /* * Note: we're applying the offset and clamping per-vertex. * Ideally, the offset is applied per-fragment prior to fragment shading. */ v0[2] = CLAMP(v0[2] + zoffset, 0.0f, 1.0f); v1[2] = CLAMP(v1[2] + zoffset, 0.0f, 1.0f); v2[2] = CLAMP(v2[2] + zoffset, 0.0f, 1.0f); stage->next->tri( stage->next, header ); }
/* Interpolate between two vertices to produce a third. */ static void interp( const struct clip_stage *clip, struct vertex_header *dst, float t, const struct vertex_header *out, const struct vertex_header *in ) { const unsigned nr_attrs = draw_current_shader_outputs(clip->stage.draw); const unsigned pos_attr = draw_current_shader_position_output(clip->stage.draw); unsigned j; /* Vertex header. */ dst->clipmask = 0; dst->edgeflag = 0; /* will get overwritten later */ dst->pad = 0; dst->vertex_id = UNDEFINED_VERTEX_ID; /* Interpolate the clip-space coords. */ interp_attr(dst->clip, t, in->clip, out->clip); /* Do the projective divide and viewport transformation to get * new window coordinates: */ { const float *pos = dst->clip; const float *scale = clip->stage.draw->viewport.scale; const float *trans = clip->stage.draw->viewport.translate; const float oow = 1.0f / pos[3]; dst->data[pos_attr][0] = pos[0] * oow * scale[0] + trans[0]; dst->data[pos_attr][1] = pos[1] * oow * scale[1] + trans[1]; dst->data[pos_attr][2] = pos[2] * oow * scale[2] + trans[2]; dst->data[pos_attr][3] = oow; } /* Other attributes */ for (j = 0; j < nr_attrs; j++) { if (j != pos_attr) interp_attr(dst->data[j], t, in->data[j], out->data[j]); } }
static void llvm_pipeline_generic(struct draw_pt_middle_end *middle, const struct draw_fetch_info *fetch_info, const struct draw_prim_info *in_prim_info) { struct llvm_middle_end *fpme = llvm_middle_end(middle); struct draw_context *draw = fpme->draw; struct draw_geometry_shader *gshader = draw->gs.geometry_shader; struct draw_prim_info gs_prim_info; struct draw_vertex_info llvm_vert_info; struct draw_vertex_info gs_vert_info; struct draw_vertex_info *vert_info; struct draw_prim_info ia_prim_info; struct draw_vertex_info ia_vert_info; const struct draw_prim_info *prim_info = in_prim_info; boolean free_prim_info = FALSE; unsigned opt = fpme->opt; unsigned clipped = 0; llvm_vert_info.count = fetch_info->count; llvm_vert_info.vertex_size = fpme->vertex_size; llvm_vert_info.stride = fpme->vertex_size; llvm_vert_info.verts = (struct vertex_header *) MALLOC(fpme->vertex_size * align(fetch_info->count, lp_native_vector_width / 32)); if (!llvm_vert_info.verts) { assert(0); return; } if (draw->collect_statistics) { draw->statistics.ia_vertices += prim_info->count; draw->statistics.ia_primitives += u_decomposed_prims_for_vertices(prim_info->prim, prim_info->count); draw->statistics.vs_invocations += fetch_info->count; } if (fetch_info->linear) clipped = fpme->current_variant->jit_func( &fpme->llvm->jit_context, llvm_vert_info.verts, draw->pt.user.vbuffer, fetch_info->start, fetch_info->count, fpme->vertex_size, draw->pt.vertex_buffer, draw->instance_id, draw->start_index, draw->start_instance); else clipped = fpme->current_variant->jit_func_elts( &fpme->llvm->jit_context, llvm_vert_info.verts, draw->pt.user.vbuffer, fetch_info->elts, draw->pt.user.eltMax, fetch_info->count, fpme->vertex_size, draw->pt.vertex_buffer, draw->instance_id, draw->pt.user.eltBias, draw->start_instance); /* Finished with fetch and vs: */ fetch_info = NULL; vert_info = &llvm_vert_info; if ((opt & PT_SHADE) && gshader) { struct draw_vertex_shader *vshader = draw->vs.vertex_shader; draw_geometry_shader_run(gshader, draw->pt.user.gs_constants, draw->pt.user.gs_constants_size, vert_info, prim_info, &vshader->info, &gs_vert_info, &gs_prim_info); FREE(vert_info->verts); vert_info = &gs_vert_info; prim_info = &gs_prim_info; } else { if (draw_prim_assembler_is_required(draw, prim_info, vert_info)) { draw_prim_assembler_run(draw, prim_info, vert_info, &ia_prim_info, &ia_vert_info); if (ia_vert_info.count) { FREE(vert_info->verts); vert_info = &ia_vert_info; prim_info = &ia_prim_info; free_prim_info = TRUE; } } } if (prim_info->count == 0) { debug_printf("GS/IA didn't emit any vertices!\n"); FREE(vert_info->verts); if (free_prim_info) { FREE(prim_info->primitive_lengths); } return; } /* stream output needs to be done before clipping */ draw_pt_so_emit( fpme->so_emit, vert_info, prim_info ); draw_stats_clipper_primitives(draw, prim_info); /* * if there's no position, need to stop now, or the latter stages * will try to access non-existent position output. */ if (draw_current_shader_position_output(draw) != -1) { if ((opt & PT_SHADE) && gshader) { clipped = draw_pt_post_vs_run( fpme->post_vs, vert_info, prim_info ); } if (clipped) { opt |= PT_PIPELINE; } /* Do we need to run the pipeline? Now will come here if clipped */ if (opt & PT_PIPELINE) { pipeline( fpme, vert_info, prim_info ); } else { emit( fpme->emit, vert_info, prim_info ); } } FREE(vert_info->verts); if (free_prim_info) { FREE(prim_info->primitive_lengths); } }
/** * Draw a wide line by drawing a quad (two triangles). */ static void wideline_line( struct draw_stage *stage, struct prim_header *header ) { /*const struct wideline_stage *wide = wideline_stage(stage);*/ const unsigned pos = draw_current_shader_position_output(stage->draw); const float half_width = 0.5f * stage->draw->rasterizer->line_width; struct prim_header tri; struct vertex_header *v0 = dup_vert(stage, header->v[0], 0); struct vertex_header *v1 = dup_vert(stage, header->v[0], 1); struct vertex_header *v2 = dup_vert(stage, header->v[1], 2); struct vertex_header *v3 = dup_vert(stage, header->v[1], 3); float *pos0 = v0->data[pos]; float *pos1 = v1->data[pos]; float *pos2 = v2->data[pos]; float *pos3 = v3->data[pos]; const float dx = fabsf(pos0[0] - pos2[0]); const float dy = fabsf(pos0[1] - pos2[1]); const boolean half_pixel_center = stage->draw->rasterizer->half_pixel_center; /* small tweak to meet GL specification */ const float bias = half_pixel_center ? 0.125f : 0.0f; /* * Draw wide line as a quad (two tris) by "stretching" the line along * X or Y. * We need to tweak coords in several ways to be conformant here. */ if (dx > dy) { /* x-major line */ pos0[1] = pos0[1] - half_width - bias; pos1[1] = pos1[1] + half_width - bias; pos2[1] = pos2[1] - half_width - bias; pos3[1] = pos3[1] + half_width - bias; if (half_pixel_center) { if (pos0[0] < pos2[0]) { /* left to right line */ pos0[0] -= 0.5f; pos1[0] -= 0.5f; pos2[0] -= 0.5f; pos3[0] -= 0.5f; } else { /* right to left line */ pos0[0] += 0.5f; pos1[0] += 0.5f; pos2[0] += 0.5f; pos3[0] += 0.5f; } } } else { /* y-major line */ pos0[0] = pos0[0] - half_width + bias; pos1[0] = pos1[0] + half_width + bias; pos2[0] = pos2[0] - half_width + bias; pos3[0] = pos3[0] + half_width + bias; if (half_pixel_center) { if (pos0[1] < pos2[1]) { /* top to bottom line */ pos0[1] -= 0.5f; pos1[1] -= 0.5f; pos2[1] -= 0.5f; pos3[1] -= 0.5f; } else { /* bottom to top line */ pos0[1] += 0.5f; pos1[1] += 0.5f; pos2[1] += 0.5f; pos3[1] += 0.5f; } } } tri.det = header->det; /* only the sign matters */ tri.v[0] = v0; tri.v[1] = v2; tri.v[2] = v3; stage->next->tri( stage->next, &tri ); tri.v[0] = v0; tri.v[1] = v3; tri.v[2] = v1; stage->next->tri( stage->next, &tri ); }
/** * Offset tri Z. Some hardware can handle this, but not usually when * doing unfilled rendering. */ static void do_offset_tri( struct draw_stage *stage, struct prim_header *header ) { const unsigned pos = draw_current_shader_position_output(stage->draw); struct offset_stage *offset = offset_stage(stage); float inv_det = 1.0f / header->det; /* Window coords: */ float *v0 = header->v[0]->data[pos]; float *v1 = header->v[1]->data[pos]; float *v2 = header->v[2]->data[pos]; /* edge vectors e = v0 - v2, f = v1 - v2 */ float ex = v0[0] - v2[0]; float ey = v0[1] - v2[1]; float ez = v0[2] - v2[2]; float fx = v1[0] - v2[0]; float fy = v1[1] - v2[1]; float fz = v1[2] - v2[2]; /* (a,b) = cross(e,f).xy */ float a = ey*fz - ez*fy; float b = ez*fx - ex*fz; float dzdx = fabsf(a * inv_det); float dzdy = fabsf(b * inv_det); float zoffset, mult; mult = MAX2(dzdx, dzdy) * offset->scale; if (stage->draw->floating_point_depth) { float bias; union fi maxz; maxz.f = MAX3(v0[2], v1[2], v2[2]); /* just do the math directly on shifted number */ maxz.ui &= 0xff << 23; maxz.i -= 23 << 23; /* Clamping to zero means mrd will be zero for very small numbers, * but specs do not indicate this should be prevented by clamping * mrd to smallest normal number instead. */ maxz.i = MAX2(maxz.i, 0); bias = offset->units * maxz.f; zoffset = bias + mult; } else { zoffset = offset->units + mult; } if (offset->clamp) zoffset = (offset->clamp < 0.0f) ? MAX2(zoffset, offset->clamp) : MIN2(zoffset, offset->clamp); /* * Note: we're applying the offset and clamping per-vertex. * Ideally, the offset is applied per-fragment prior to fragment shading. */ v0[2] = CLAMP(v0[2] + zoffset, 0.0f, 1.0f); v1[2] = CLAMP(v1[2] + zoffset, 0.0f, 1.0f); v2[2] = CLAMP(v2[2] + zoffset, 0.0f, 1.0f); stage->next->tri( stage->next, header ); }
static void fetch_pipeline_generic( struct draw_pt_middle_end *middle, const struct draw_fetch_info *fetch_info, const struct draw_prim_info *prim_info ) { struct fetch_pipeline_middle_end *fpme = (struct fetch_pipeline_middle_end *)middle; struct draw_context *draw = fpme->draw; struct draw_vertex_shader *vshader = draw->vs.vertex_shader; struct draw_geometry_shader *gshader = draw->gs.geometry_shader; struct draw_prim_info gs_prim_info; struct draw_vertex_info fetched_vert_info; struct draw_vertex_info vs_vert_info; struct draw_vertex_info gs_vert_info; struct draw_vertex_info *vert_info; unsigned opt = fpme->opt; fetched_vert_info.count = fetch_info->count; fetched_vert_info.vertex_size = fpme->vertex_size; fetched_vert_info.stride = fpme->vertex_size; fetched_vert_info.verts = (struct vertex_header *)MALLOC(fpme->vertex_size * align(fetch_info->count, 4)); if (!fetched_vert_info.verts) { assert(0); return; } /* Fetch into our vertex buffer. */ fetch( fpme->fetch, fetch_info, (char *)fetched_vert_info.verts ); /* Finished with fetch: */ fetch_info = NULL; vert_info = &fetched_vert_info; /* Run the shader, note that this overwrites the data[] parts of * the pipeline verts. */ if (fpme->opt & PT_SHADE) { draw_vertex_shader_run(vshader, draw->pt.user.vs_constants, draw->pt.user.vs_constants_size, vert_info, &vs_vert_info); FREE(vert_info->verts); vert_info = &vs_vert_info; } if ((fpme->opt & PT_SHADE) && gshader) { draw_geometry_shader_run(gshader, draw->pt.user.gs_constants, draw->pt.user.gs_constants_size, vert_info, prim_info, &gs_vert_info, &gs_prim_info); FREE(vert_info->verts); vert_info = &gs_vert_info; prim_info = &gs_prim_info; } /* Stream output needs to be done before clipping. * * XXX: Stream output surely needs to respect the prim_info->elt * lists. */ draw_pt_so_emit( fpme->so_emit, vert_info, prim_info ); /* * if there's no position, need to stop now, or the latter stages * will try to access non-existent position output. */ if (draw_current_shader_position_output(draw) != -1) { if (draw_pt_post_vs_run( fpme->post_vs, vert_info )) { opt |= PT_PIPELINE; } /* Do we need to run the pipeline? */ if (opt & PT_PIPELINE) { pipeline( fpme, vert_info, prim_info ); } else { emit( fpme->emit, vert_info, prim_info ); } } FREE(vert_info->verts); }
/* Interpolate between two vertices to produce a third. */ static void interp( const struct clip_stage *clip, struct vertex_header *dst, float t, const struct vertex_header *out, const struct vertex_header *in, unsigned viewport_index ) { const unsigned nr_attrs = draw_num_shader_outputs(clip->stage.draw); const unsigned pos_attr = draw_current_shader_position_output(clip->stage.draw); const unsigned clip_attr = draw_current_shader_clipvertex_output(clip->stage.draw); unsigned j; float t_nopersp; /* Vertex header. */ dst->clipmask = 0; dst->edgeflag = 0; /* will get overwritten later */ dst->have_clipdist = in->have_clipdist; dst->vertex_id = UNDEFINED_VERTEX_ID; /* Interpolate the clip-space coords. */ interp_attr(dst->clip, t, in->clip, out->clip); /* interpolate the clip-space position */ interp_attr(dst->pre_clip_pos, t, in->pre_clip_pos, out->pre_clip_pos); /* Do the projective divide and viewport transformation to get * new window coordinates: */ { const float *pos = dst->pre_clip_pos; const float *scale = clip->stage.draw->viewports[viewport_index].scale; const float *trans = clip->stage.draw->viewports[viewport_index].translate; const float oow = 1.0f / pos[3]; dst->data[pos_attr][0] = pos[0] * oow * scale[0] + trans[0]; dst->data[pos_attr][1] = pos[1] * oow * scale[1] + trans[1]; dst->data[pos_attr][2] = pos[2] * oow * scale[2] + trans[2]; dst->data[pos_attr][3] = oow; } /** * Compute the t in screen-space instead of 3d space to use * for noperspective interpolation. * * The points can be aligned with the X axis, so in that case try * the Y. When both points are at the same screen position, we can * pick whatever value (the interpolated point won't be in front * anyway), so just use the 3d t. */ { int k; t_nopersp = t; /* find either in.x != out.x or in.y != out.y */ for (k = 0; k < 2; k++) { if (in->clip[k] != out->clip[k]) { /* do divide by W, then compute linear interpolation factor */ float in_coord = in->clip[k] / in->clip[3]; float out_coord = out->clip[k] / out->clip[3]; float dst_coord = dst->clip[k] / dst->clip[3]; t_nopersp = (dst_coord - out_coord) / (in_coord - out_coord); break; } } } /* Other attributes */ for (j = 0; j < nr_attrs; j++) { if (j != pos_attr && j != clip_attr) { if (clip->noperspective_attribs[j]) interp_attr(dst->data[j], t_nopersp, in->data[j], out->data[j]); else interp_attr(dst->data[j], t, in->data[j], out->data[j]); } } }
/* If there are lots of sprite points (and why wouldn't there be?) it * would probably be more sensible to change hardware setup to * optimize this rather than doing the whole thing in software like * this. */ static void widepoint_point( struct draw_stage *stage, struct prim_header *header ) { const struct widepoint_stage *wide = widepoint_stage(stage); const unsigned pos = draw_current_shader_position_output(stage->draw); const boolean sprite = (boolean) stage->draw->rasterizer->point_quad_rasterization; float half_size; float left_adj, right_adj, bot_adj, top_adj; struct prim_header tri; /* four dups of original vertex */ struct vertex_header *v0 = dup_vert(stage, header->v[0], 0); struct vertex_header *v1 = dup_vert(stage, header->v[0], 1); struct vertex_header *v2 = dup_vert(stage, header->v[0], 2); struct vertex_header *v3 = dup_vert(stage, header->v[0], 3); float *pos0 = v0->data[pos]; float *pos1 = v1->data[pos]; float *pos2 = v2->data[pos]; float *pos3 = v3->data[pos]; /* point size is either per-vertex or fixed size */ if (wide->psize_slot >= 0) { half_size = header->v[0]->data[wide->psize_slot][0]; half_size *= 0.5f; } else { half_size = wide->half_point_size; } left_adj = -half_size + wide->xbias; right_adj = half_size + wide->xbias; bot_adj = half_size + wide->ybias; top_adj = -half_size + wide->ybias; pos0[0] += left_adj; pos0[1] += top_adj; pos1[0] += left_adj; pos1[1] += bot_adj; pos2[0] += right_adj; pos2[1] += top_adj; pos3[0] += right_adj; pos3[1] += bot_adj; if (sprite) { static const float tex00[4] = { 0, 0, 0, 1 }; static const float tex01[4] = { 0, 1, 0, 1 }; static const float tex11[4] = { 1, 1, 0, 1 }; static const float tex10[4] = { 1, 0, 0, 1 }; set_texcoords( wide, v0, tex00 ); set_texcoords( wide, v1, tex01 ); set_texcoords( wide, v2, tex10 ); set_texcoords( wide, v3, tex11 ); } tri.det = header->det; /* only the sign matters */ tri.v[0] = v0; tri.v[1] = v2; tri.v[2] = v3; stage->next->tri( stage->next, &tri ); tri.v[0] = v0; tri.v[1] = v3; tri.v[2] = v1; stage->next->tri( stage->next, &tri ); }
static void llvm_pipeline_generic( struct draw_pt_middle_end *middle, const struct draw_fetch_info *fetch_info, const struct draw_prim_info *prim_info ) { struct llvm_middle_end *fpme = (struct llvm_middle_end *)middle; struct draw_context *draw = fpme->draw; struct draw_geometry_shader *gshader = draw->gs.geometry_shader; struct draw_prim_info gs_prim_info; struct draw_vertex_info llvm_vert_info; struct draw_vertex_info gs_vert_info; struct draw_vertex_info *vert_info; unsigned opt = fpme->opt; unsigned clipped = 0; llvm_vert_info.count = fetch_info->count; llvm_vert_info.vertex_size = fpme->vertex_size; llvm_vert_info.stride = fpme->vertex_size; llvm_vert_info.verts = (struct vertex_header *)MALLOC(fpme->vertex_size * align(fetch_info->count, lp_native_vector_width / 32)); if (!llvm_vert_info.verts) { assert(0); return; } if (fetch_info->linear) clipped = fpme->current_variant->jit_func( &fpme->llvm->jit_context, llvm_vert_info.verts, (const char **)draw->pt.user.vbuffer, fetch_info->start, fetch_info->count, fpme->vertex_size, draw->pt.vertex_buffer, draw->instance_id); else clipped = fpme->current_variant->jit_func_elts( &fpme->llvm->jit_context, llvm_vert_info.verts, (const char **)draw->pt.user.vbuffer, fetch_info->elts, fetch_info->count, fpme->vertex_size, draw->pt.vertex_buffer, draw->instance_id); /* Finished with fetch and vs: */ fetch_info = NULL; vert_info = &llvm_vert_info; if ((opt & PT_SHADE) && gshader) { struct draw_vertex_shader *vshader = draw->vs.vertex_shader; draw_geometry_shader_run(gshader, draw->pt.user.gs_constants, draw->pt.user.gs_constants_size, vert_info, prim_info, &vshader->info, &gs_vert_info, &gs_prim_info); FREE(vert_info->verts); vert_info = &gs_vert_info; prim_info = &gs_prim_info; } /* stream output needs to be done before clipping */ draw_pt_so_emit( fpme->so_emit, vert_info, prim_info ); /* * if there's no position, need to stop now, or the latter stages * will try to access non-existent position output. */ if (draw_current_shader_position_output(draw) != -1) { if ((opt & PT_SHADE) && gshader) { clipped = draw_pt_post_vs_run( fpme->post_vs, vert_info ); } if (clipped) { opt |= PT_PIPELINE; } /* Do we need to run the pipeline? Now will come here if clipped */ if (opt & PT_PIPELINE) { pipeline( fpme, vert_info, prim_info ); } else { emit( fpme->emit, vert_info, prim_info ); } } FREE(vert_info->verts); }