Path: blob/21.2-virgl/src/gallium/auxiliary/draw/draw_pipe_wide_point.c
4565 views
/**************************************************************************1*2* Copyright 2007 VMware, Inc.3* All Rights Reserved.4*5* Permission is hereby granted, free of charge, to any person obtaining a6* copy of this software and associated documentation files (the7* "Software"), to deal in the Software without restriction, including8* without limitation the rights to use, copy, modify, merge, publish,9* distribute, sub license, and/or sell copies of the Software, and to10* permit persons to whom the Software is furnished to do so, subject to11* the following conditions:12*13* The above copyright notice and this permission notice (including the14* next paragraph) shall be included in all copies or substantial portions15* of the Software.16*17* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS18* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF19* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT.20* IN NO EVENT SHALL VMWARE AND/OR ITS SUPPLIERS BE LIABLE FOR21* ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,22* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE23* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.24*25**************************************************************************/2627/* Authors: Keith Whitwell <[email protected]>28*/2930/**31* Notes on wide points and sprite mode:32*33* In wide point/sprite mode we effectively need to convert each incoming34* vertex into four outgoing vertices specifying the corners of a quad.35* Since we don't (yet) have geometry shaders, we have to handle this here36* in the draw module.37*38* For sprites, it also means that this is where we have to handle texcoords39* for the vertices of the quad. OpenGL's GL_COORD_REPLACE state specifies40* if/how enabled texcoords are automatically generated for sprites. We pass41* that info through gallium in the pipe_rasterizer_state::sprite_coord_mode42* array.43*44* Additionally, GLSL's gl_PointCoord fragment attribute has to be handled45* here as well. This is basically an additional texture/generic attribute46* that varies .x from 0 to 1 horizontally across the point and varies .y47* vertically from 0 to 1 down the sprite.48*49* With geometry shaders, the gallium frontends could create a GS to do50* most/all of this.51*/525354#include "pipe/p_screen.h"55#include "pipe/p_context.h"56#include "util/u_math.h"57#include "util/u_memory.h"58#include "pipe/p_defines.h"59#include "pipe/p_shader_tokens.h"60#include "draw_fs.h"61#include "draw_vs.h"62#include "draw_pipe.h"636465struct widepoint_stage {66struct draw_stage stage; /**< base class */6768float half_point_size;6970float xbias;71float ybias;7273/** for automatic texcoord generation/replacement */74uint num_texcoord_gen;75uint texcoord_gen_slot[PIPE_MAX_SHADER_OUTPUTS];7677/* TGSI_SEMANTIC to which sprite_coord_enable applies */78enum tgsi_semantic sprite_coord_semantic;7980int psize_slot;81};82838485static inline struct widepoint_stage *86widepoint_stage( struct draw_stage *stage )87{88return (struct widepoint_stage *)stage;89}909192/**93* Set the vertex texcoords for sprite mode.94* Coords may be left untouched or set to a right-side-up or upside-down95* orientation.96*/97static void set_texcoords(const struct widepoint_stage *wide,98struct vertex_header *v, const float tc[4])99{100const struct draw_context *draw = wide->stage.draw;101const struct pipe_rasterizer_state *rast = draw->rasterizer;102const uint texcoord_mode = rast->sprite_coord_mode;103uint i;104105for (i = 0; i < wide->num_texcoord_gen; i++) {106const uint slot = wide->texcoord_gen_slot[i];107v->data[slot][0] = tc[0];108if (texcoord_mode == PIPE_SPRITE_COORD_LOWER_LEFT)109v->data[slot][1] = 1.0f - tc[1];110else111v->data[slot][1] = tc[1];112v->data[slot][2] = tc[2];113v->data[slot][3] = tc[3];114}115}116117118/* If there are lots of sprite points (and why wouldn't there be?) it119* would probably be more sensible to change hardware setup to120* optimize this rather than doing the whole thing in software like121* this.122*/123static void widepoint_point( struct draw_stage *stage,124struct prim_header *header )125{126const struct widepoint_stage *wide = widepoint_stage(stage);127const unsigned pos = draw_current_shader_position_output(stage->draw);128const boolean sprite = (boolean) stage->draw->rasterizer->point_quad_rasterization;129float half_size;130float left_adj, right_adj, bot_adj, top_adj;131132struct prim_header tri;133134/* four dups of original vertex */135struct vertex_header *v0 = dup_vert(stage, header->v[0], 0);136struct vertex_header *v1 = dup_vert(stage, header->v[0], 1);137struct vertex_header *v2 = dup_vert(stage, header->v[0], 2);138struct vertex_header *v3 = dup_vert(stage, header->v[0], 3);139140float *pos0 = v0->data[pos];141float *pos1 = v1->data[pos];142float *pos2 = v2->data[pos];143float *pos3 = v3->data[pos];144145/* point size is either per-vertex or fixed size */146if (wide->psize_slot >= 0) {147half_size = header->v[0]->data[wide->psize_slot][0];148half_size *= 0.5f;149}150else {151half_size = wide->half_point_size;152}153154left_adj = -half_size + wide->xbias;155right_adj = half_size + wide->xbias;156bot_adj = half_size + wide->ybias;157top_adj = -half_size + wide->ybias;158159pos0[0] += left_adj;160pos0[1] += top_adj;161162pos1[0] += left_adj;163pos1[1] += bot_adj;164165pos2[0] += right_adj;166pos2[1] += top_adj;167168pos3[0] += right_adj;169pos3[1] += bot_adj;170171if (sprite) {172static const float tex00[4] = { 0, 0, 0, 1 };173static const float tex01[4] = { 0, 1, 0, 1 };174static const float tex11[4] = { 1, 1, 0, 1 };175static const float tex10[4] = { 1, 0, 0, 1 };176set_texcoords( wide, v0, tex00 );177set_texcoords( wide, v1, tex01 );178set_texcoords( wide, v2, tex10 );179set_texcoords( wide, v3, tex11 );180}181182tri.det = header->det; /* only the sign matters */183tri.v[0] = v0;184tri.v[1] = v2;185tri.v[2] = v3;186stage->next->tri( stage->next, &tri );187188tri.v[0] = v0;189tri.v[1] = v3;190tri.v[2] = v1;191stage->next->tri( stage->next, &tri );192}193194195static void196widepoint_first_point(struct draw_stage *stage,197struct prim_header *header)198{199struct widepoint_stage *wide = widepoint_stage(stage);200struct draw_context *draw = stage->draw;201struct pipe_context *pipe = draw->pipe;202const struct pipe_rasterizer_state *rast = draw->rasterizer;203void *r;204205wide->half_point_size = 0.5f * rast->point_size;206wide->xbias = 0.0;207wide->ybias = 0.0;208209if (rast->half_pixel_center) {210wide->xbias = 0.125;211wide->ybias = -0.125;212}213214/* Disable triangle culling, stippling, unfilled mode etc. */215r = draw_get_rasterizer_no_cull(draw, rast);216draw->suspend_flushing = TRUE;217pipe->bind_rasterizer_state(pipe, r);218draw->suspend_flushing = FALSE;219220/* XXX we won't know the real size if it's computed by the vertex shader! */221if ((rast->point_size > draw->pipeline.wide_point_threshold) ||222(rast->point_quad_rasterization && draw->pipeline.point_sprite)) {223stage->point = widepoint_point;224}225else {226stage->point = draw_pipe_passthrough_point;227}228229draw_remove_extra_vertex_attribs(draw);230231if (rast->point_quad_rasterization) {232const struct draw_fragment_shader *fs = draw->fs.fragment_shader;233uint i;234235assert(fs);236237wide->num_texcoord_gen = 0;238239/* Loop over fragment shader inputs looking for the PCOORD input or inputs240* for which bit 'k' in sprite_coord_enable is set.241*/242for (i = 0; i < fs->info.num_inputs; i++) {243int slot;244const enum tgsi_semantic sn = fs->info.input_semantic_name[i];245const unsigned si = fs->info.input_semantic_index[i];246247if (sn == wide->sprite_coord_semantic) {248/* Note that sprite_coord_enable is a bitfield of 32 bits. */249if (si >= 32 || !(rast->sprite_coord_enable & (1 << si)))250continue;251} else if (sn != TGSI_SEMANTIC_PCOORD) {252continue;253}254255/* OK, this generic attribute needs to be replaced with a256* sprite coord (see above).257*/258slot = draw_alloc_extra_vertex_attrib(draw, sn, si);259260/* add this slot to the texcoord-gen list */261wide->texcoord_gen_slot[wide->num_texcoord_gen++] = slot;262}263}264265wide->psize_slot = -1;266if (rast->point_size_per_vertex) {267/* find PSIZ vertex output */268wide->psize_slot = draw_find_shader_output(draw, TGSI_SEMANTIC_PSIZE, 0);269}270271stage->point( stage, header );272}273274275static void widepoint_flush( struct draw_stage *stage, unsigned flags )276{277struct draw_context *draw = stage->draw;278struct pipe_context *pipe = draw->pipe;279280stage->point = widepoint_first_point;281stage->next->flush( stage->next, flags );282283draw_remove_extra_vertex_attribs(draw);284285/* restore original rasterizer state */286if (draw->rast_handle) {287draw->suspend_flushing = TRUE;288pipe->bind_rasterizer_state(pipe, draw->rast_handle);289draw->suspend_flushing = FALSE;290}291}292293294static void widepoint_reset_stipple_counter( struct draw_stage *stage )295{296stage->next->reset_stipple_counter( stage->next );297}298299300static void widepoint_destroy( struct draw_stage *stage )301{302draw_free_temp_verts( stage );303FREE( stage );304}305306307struct draw_stage *draw_wide_point_stage( struct draw_context *draw )308{309struct widepoint_stage *wide = CALLOC_STRUCT(widepoint_stage);310if (!wide)311goto fail;312313wide->stage.draw = draw;314wide->stage.name = "wide-point";315wide->stage.next = NULL;316wide->stage.point = widepoint_first_point;317wide->stage.line = draw_pipe_passthrough_line;318wide->stage.tri = draw_pipe_passthrough_tri;319wide->stage.flush = widepoint_flush;320wide->stage.reset_stipple_counter = widepoint_reset_stipple_counter;321wide->stage.destroy = widepoint_destroy;322323if (!draw_alloc_temp_verts( &wide->stage, 4 ))324goto fail;325326wide->sprite_coord_semantic =327draw->pipe->screen->get_param(draw->pipe->screen, PIPE_CAP_TGSI_TEXCOORD)328?329TGSI_SEMANTIC_TEXCOORD : TGSI_SEMANTIC_GENERIC;330331return &wide->stage;332333fail:334if (wide)335wide->stage.destroy( &wide->stage );336337return NULL;338}339340341