/** * Called via ctx->Driver.DrawAtlasBitmap() */ static void st_DrawAtlasBitmaps(struct gl_context *ctx, const struct gl_bitmap_atlas *atlas, GLuint count, const GLubyte *ids) { struct st_context *st = st_context(ctx); struct pipe_context *pipe = st->pipe; struct st_texture_object *stObj = st_texture_object(atlas->texObj); struct pipe_sampler_view *sv; /* convert Z from [0,1] to [-1,-1] to match viewport Z scale/bias */ const float z = ctx->Current.RasterPos[2] * 2.0f - 1.0f; const float *color = ctx->Current.RasterColor; const float clip_x_scale = 2.0f / st->state.fb_width; const float clip_y_scale = 2.0f / st->state.fb_height; const unsigned num_verts = count * 4; const unsigned num_vert_bytes = num_verts * sizeof(struct st_util_vertex); struct st_util_vertex *verts; struct pipe_vertex_buffer vb = {0}; unsigned i; if (!st->bitmap.vs) { init_bitmap_state(st); } st_flush_bitmap_cache(st); st_validate_state(st, ST_PIPELINE_META); st_invalidate_readpix_cache(st); sv = st_create_texture_sampler_view(pipe, stObj->pt); if (!sv) { _mesa_error(ctx, GL_OUT_OF_MEMORY, "glCallLists(bitmap text)"); return; } setup_render_state(ctx, sv, color, true); vb.stride = sizeof(struct st_util_vertex); u_upload_alloc(pipe->stream_uploader, 0, num_vert_bytes, 4, &vb.buffer_offset, &vb.buffer.resource, (void **) &verts); if (unlikely(!verts)) { _mesa_error(ctx, GL_OUT_OF_MEMORY, "glCallLists(bitmap text)"); goto out; } /* build quads vertex data */ for (i = 0; i < count; i++) { const GLfloat epsilon = 0.0001F; const struct gl_bitmap_glyph *g = &atlas->glyphs[ids[i]]; const float xmove = g->xmove, ymove = g->ymove; const float xorig = g->xorig, yorig = g->yorig; const float s0 = g->x, t0 = g->y; const float s1 = s0 + g->w, t1 = t0 + g->h; const float x0 = IFLOOR(ctx->Current.RasterPos[0] - xorig + epsilon); const float y0 = IFLOOR(ctx->Current.RasterPos[1] - yorig + epsilon); const float x1 = x0 + g->w, y1 = y0 + g->h; const float clip_x0 = x0 * clip_x_scale - 1.0f; const float clip_y0 = y0 * clip_y_scale - 1.0f; const float clip_x1 = x1 * clip_x_scale - 1.0f; const float clip_y1 = y1 * clip_y_scale - 1.0f; /* lower-left corner */ verts->x = clip_x0; verts->y = clip_y0; verts->z = z; verts->r = color[0]; verts->g = color[1]; verts->b = color[2]; verts->a = color[3]; verts->s = s0; verts->t = t0; verts++; /* lower-right corner */ verts->x = clip_x1; verts->y = clip_y0; verts->z = z; verts->r = color[0]; verts->g = color[1]; verts->b = color[2]; verts->a = color[3]; verts->s = s1; verts->t = t0; verts++; /* upper-right corner */ verts->x = clip_x1; verts->y = clip_y1; verts->z = z; verts->r = color[0]; verts->g = color[1]; verts->b = color[2]; verts->a = color[3]; verts->s = s1; verts->t = t1; verts++; /* upper-left corner */ verts->x = clip_x0; verts->y = clip_y1; verts->z = z; verts->r = color[0]; verts->g = color[1]; verts->b = color[2]; verts->a = color[3]; verts->s = s0; verts->t = t1; verts++; /* Update the raster position */ ctx->Current.RasterPos[0] += xmove; ctx->Current.RasterPos[1] += ymove; } u_upload_unmap(pipe->stream_uploader); cso_set_vertex_buffers(st->cso_context, cso_get_aux_vertex_buffer_slot(st->cso_context), 1, &vb); cso_draw_arrays(st->cso_context, PIPE_PRIM_QUADS, 0, num_verts); out: restore_render_state(ctx); pipe_resource_reference(&vb.buffer.resource, NULL); pipe_sampler_view_reference(&sv, NULL); /* We uploaded modified constants, need to invalidate them. */ st->dirty |= ST_NEW_FS_CONSTANTS; }
/** * Create a mipmap generation context. * The idea is to create one of these and re-use it each time we need to * generate a mipmap. */ struct gen_mipmap_state * util_create_gen_mipmap(struct pipe_context *pipe, struct cso_context *cso) { struct gen_mipmap_state *ctx; uint i; ctx = CALLOC_STRUCT(gen_mipmap_state); if (!ctx) return NULL; ctx->pipe = pipe; ctx->cso = cso; /* disabled blending/masking */ memset(&ctx->blend_keep_color, 0, sizeof(ctx->blend_keep_color)); memset(&ctx->blend_write_color, 0, sizeof(ctx->blend_write_color)); ctx->blend_write_color.rt[0].colormask = PIPE_MASK_RGBA; /* no-op depth/stencil/alpha */ memset(&ctx->dsa_keep_depth, 0, sizeof(ctx->dsa_keep_depth)); memset(&ctx->dsa_write_depth, 0, sizeof(ctx->dsa_write_depth)); ctx->dsa_write_depth.depth.enabled = 1; ctx->dsa_write_depth.depth.func = PIPE_FUNC_ALWAYS; ctx->dsa_write_depth.depth.writemask = 1; /* rasterizer */ memset(&ctx->rasterizer, 0, sizeof(ctx->rasterizer)); ctx->rasterizer.cull_face = PIPE_FACE_NONE; ctx->rasterizer.half_pixel_center = 1; ctx->rasterizer.bottom_edge_rule = 1; ctx->rasterizer.depth_clip = 1; /* sampler state */ memset(&ctx->sampler, 0, sizeof(ctx->sampler)); ctx->sampler.wrap_s = PIPE_TEX_WRAP_CLAMP_TO_EDGE; ctx->sampler.wrap_t = PIPE_TEX_WRAP_CLAMP_TO_EDGE; ctx->sampler.wrap_r = PIPE_TEX_WRAP_CLAMP_TO_EDGE; ctx->sampler.min_mip_filter = PIPE_TEX_MIPFILTER_NEAREST; ctx->sampler.normalized_coords = 1; /* vertex elements state */ memset(&ctx->velem[0], 0, sizeof(ctx->velem[0]) * 2); for (i = 0; i < 2; i++) { ctx->velem[i].src_offset = i * 4 * sizeof(float); ctx->velem[i].instance_divisor = 0; ctx->velem[i].vertex_buffer_index = cso_get_aux_vertex_buffer_slot(cso); ctx->velem[i].src_format = PIPE_FORMAT_R32G32B32A32_FLOAT; } /* vertex data that doesn't change */ for (i = 0; i < 4; i++) { ctx->vertices[i][0][2] = 0.0f; /* z */ ctx->vertices[i][0][3] = 1.0f; /* w */ ctx->vertices[i][1][3] = 1.0f; /* q */ } /* Note: the actual vertex buffer is allocated as needed below */ return ctx; }
/** * Draw a quad with given position, texcoords and color. */ bool st_draw_quad(struct st_context *st, float x0, float y0, float x1, float y1, float z, float s0, float t0, float s1, float t1, const float *color, unsigned num_instances) { struct pipe_vertex_buffer vb = {0}; struct st_util_vertex *verts; vb.stride = sizeof(struct st_util_vertex); u_upload_alloc(st->uploader, 0, 4 * sizeof(struct st_util_vertex), 4, &vb.buffer_offset, &vb.buffer, (void **) &verts); if (!vb.buffer) { return false; } /* lower-left */ verts[0].x = x0; verts[0].y = y1; verts[0].z = z; verts[0].r = color[0]; verts[0].g = color[1]; verts[0].b = color[2]; verts[0].a = color[3]; verts[0].s = s0; verts[0].t = t0; /* lower-right */ verts[1].x = x1; verts[1].y = y1; verts[1].z = z; verts[1].r = color[0]; verts[1].g = color[1]; verts[1].b = color[2]; verts[1].a = color[3]; verts[1].s = s1; verts[1].t = t0; /* upper-right */ verts[2].x = x1; verts[2].y = y0; verts[2].z = z; verts[2].r = color[0]; verts[2].g = color[1]; verts[2].b = color[2]; verts[2].a = color[3]; verts[2].s = s1; verts[2].t = t1; /* upper-left */ verts[3].x = x0; verts[3].y = y0; verts[3].z = z; verts[3].r = color[0]; verts[3].g = color[1]; verts[3].b = color[2]; verts[3].a = color[3]; verts[3].s = s0; verts[3].t = t1; u_upload_unmap(st->uploader); /* At the time of writing, cso_get_aux_vertex_buffer_slot() always returns * zero. If that ever changes we need to audit the calls to that function * and make sure the slot number is used consistently everywhere. */ assert(cso_get_aux_vertex_buffer_slot(st->cso_context) == 0); cso_set_vertex_buffers(st->cso_context, cso_get_aux_vertex_buffer_slot(st->cso_context), 1, &vb); if (num_instances > 1) { cso_draw_arrays_instanced(st->cso_context, PIPE_PRIM_TRIANGLE_FAN, 0, 4, 0, num_instances); } else { cso_draw_arrays(st->cso_context, PIPE_PRIM_TRIANGLE_FAN, 0, 4); } pipe_resource_reference(&vb.buffer, NULL); return true; }
/** * Generate mipmap images. It's assumed all needed texture memory is * already allocated. * * \param psv the sampler view to the texture to generate mipmap levels for * \param face which cube face to generate mipmaps for (0 for non-cube maps) * \param baseLevel the first mipmap level to use as a src * \param lastLevel the last mipmap level to generate * \param filter the minification filter used to generate mipmap levels with * \param filter one of PIPE_TEX_FILTER_LINEAR, PIPE_TEX_FILTER_NEAREST */ void util_gen_mipmap(struct gen_mipmap_state *ctx, struct pipe_sampler_view *psv, uint face, uint baseLevel, uint lastLevel, uint filter) { struct pipe_context *pipe = ctx->pipe; struct pipe_screen *screen = pipe->screen; struct pipe_framebuffer_state fb; struct pipe_resource *pt = psv->texture; uint dstLevel; uint offset; uint type; boolean is_depth = util_format_is_depth_or_stencil(psv->format); /* The texture object should have room for the levels which we're * about to generate. */ assert(lastLevel <= pt->last_level); /* If this fails, why are we here? */ assert(lastLevel > baseLevel); assert(filter == PIPE_TEX_FILTER_LINEAR || filter == PIPE_TEX_FILTER_NEAREST); type = util_pipe_tex_to_tgsi_tex(pt->target, 1); /* check if we can render in the texture's format */ if (!screen->is_format_supported(screen, psv->format, pt->target, pt->nr_samples, is_depth ? PIPE_BIND_DEPTH_STENCIL : PIPE_BIND_RENDER_TARGET)) { /* The caller should check if the format is renderable. */ assert(0); return; } /* save state (restored below) */ cso_save_blend(ctx->cso); cso_save_depth_stencil_alpha(ctx->cso); cso_save_rasterizer(ctx->cso); cso_save_sample_mask(ctx->cso); cso_save_samplers(ctx->cso, PIPE_SHADER_FRAGMENT); cso_save_sampler_views(ctx->cso, PIPE_SHADER_FRAGMENT); cso_save_stream_outputs(ctx->cso); cso_save_framebuffer(ctx->cso); cso_save_fragment_shader(ctx->cso); cso_save_vertex_shader(ctx->cso); cso_save_geometry_shader(ctx->cso); cso_save_viewport(ctx->cso); cso_save_vertex_elements(ctx->cso); cso_save_aux_vertex_buffer_slot(ctx->cso); cso_save_render_condition(ctx->cso); /* bind our state */ cso_set_blend(ctx->cso, is_depth ? &ctx->blend_keep_color : &ctx->blend_write_color); cso_set_depth_stencil_alpha(ctx->cso, is_depth ? &ctx->dsa_write_depth : &ctx->dsa_keep_depth); cso_set_rasterizer(ctx->cso, &ctx->rasterizer); cso_set_sample_mask(ctx->cso, ~0); cso_set_vertex_elements(ctx->cso, 2, ctx->velem); cso_set_stream_outputs(ctx->cso, 0, NULL, NULL); cso_set_render_condition(ctx->cso, NULL, FALSE, 0); set_fragment_shader(ctx, type, is_depth); set_vertex_shader(ctx); cso_set_geometry_shader_handle(ctx->cso, NULL); /* init framebuffer state */ memset(&fb, 0, sizeof(fb)); /* set min/mag to same filter for faster sw speed */ ctx->sampler.mag_img_filter = filter; ctx->sampler.min_img_filter = filter; for (dstLevel = baseLevel + 1; dstLevel <= lastLevel; dstLevel++) { const uint srcLevel = dstLevel - 1; struct pipe_viewport_state vp; unsigned nr_layers, layer, i; float rcoord = 0.0f; if (pt->target == PIPE_TEXTURE_3D) nr_layers = u_minify(pt->depth0, dstLevel); else if (pt->target == PIPE_TEXTURE_2D_ARRAY || pt->target == PIPE_TEXTURE_1D_ARRAY || pt->target == PIPE_TEXTURE_CUBE_ARRAY) nr_layers = pt->array_size; else nr_layers = 1; for (i = 0; i < nr_layers; i++) { struct pipe_surface *surf, surf_templ; if (pt->target == PIPE_TEXTURE_3D) { /* in theory with geom shaders and driver with full layer support could do that in one go. */ layer = i; /* XXX hmm really? */ rcoord = (float)layer / (float)nr_layers + 1.0f / (float)(nr_layers * 2); } else if (pt->target == PIPE_TEXTURE_2D_ARRAY || pt->target == PIPE_TEXTURE_1D_ARRAY) { layer = i; rcoord = (float)layer; } else if (pt->target == PIPE_TEXTURE_CUBE_ARRAY) { layer = i; face = layer % 6; rcoord = layer / 6; } else layer = face; u_surface_default_template(&surf_templ, pt); surf_templ.u.tex.level = dstLevel; surf_templ.u.tex.first_layer = layer; surf_templ.u.tex.last_layer = layer; surf = pipe->create_surface(pipe, pt, &surf_templ); /* * Setup framebuffer / dest surface */ if (is_depth) { fb.nr_cbufs = 0; fb.zsbuf = surf; } else { fb.nr_cbufs = 1; fb.cbufs[0] = surf; } fb.width = u_minify(pt->width0, dstLevel); fb.height = u_minify(pt->height0, dstLevel); cso_set_framebuffer(ctx->cso, &fb); /* viewport */ vp.scale[0] = 0.5f * fb.width; vp.scale[1] = 0.5f * fb.height; vp.scale[2] = 1.0f; vp.scale[3] = 1.0f; vp.translate[0] = 0.5f * fb.width; vp.translate[1] = 0.5f * fb.height; vp.translate[2] = 0.0f; vp.translate[3] = 0.0f; cso_set_viewport(ctx->cso, &vp); /* * Setup sampler state * Note: we should only have to set the min/max LOD clamps to ensure * we grab texels from the right mipmap level. But some hardware * has trouble with min clamping so we also set the lod_bias to * try to work around that. */ ctx->sampler.min_lod = ctx->sampler.max_lod = (float) srcLevel; ctx->sampler.lod_bias = (float) srcLevel; cso_single_sampler(ctx->cso, PIPE_SHADER_FRAGMENT, 0, &ctx->sampler); cso_single_sampler_done(ctx->cso, PIPE_SHADER_FRAGMENT); cso_set_sampler_views(ctx->cso, PIPE_SHADER_FRAGMENT, 1, &psv); /* quad coords in clip coords */ offset = set_vertex_data(ctx, pt->target, face, rcoord); util_draw_vertex_buffer(ctx->pipe, ctx->cso, ctx->vbuf, cso_get_aux_vertex_buffer_slot(ctx->cso), offset, PIPE_PRIM_TRIANGLE_FAN, 4, /* verts */ 2); /* attribs/vert */ /* need to signal that the texture has changed _after_ rendering to it */ pipe_surface_reference( &surf, NULL ); } } /* restore state we changed */ cso_restore_blend(ctx->cso); cso_restore_depth_stencil_alpha(ctx->cso); cso_restore_rasterizer(ctx->cso); cso_restore_sample_mask(ctx->cso); cso_restore_samplers(ctx->cso, PIPE_SHADER_FRAGMENT); cso_restore_sampler_views(ctx->cso, PIPE_SHADER_FRAGMENT); cso_restore_framebuffer(ctx->cso); cso_restore_fragment_shader(ctx->cso); cso_restore_vertex_shader(ctx->cso); cso_restore_geometry_shader(ctx->cso); cso_restore_viewport(ctx->cso); cso_restore_vertex_elements(ctx->cso); cso_restore_stream_outputs(ctx->cso); cso_restore_aux_vertex_buffer_slot(ctx->cso); cso_restore_render_condition(ctx->cso); }
static struct st_context * st_create_context_priv( struct gl_context *ctx, struct pipe_context *pipe, const struct st_config_options *options) { struct pipe_screen *screen = pipe->screen; uint i; struct st_context *st = ST_CALLOC_STRUCT( st_context ); st->options = *options; ctx->st = st; st->ctx = ctx; st->pipe = pipe; /* XXX: this is one-off, per-screen init: */ st_debug_init(); /* state tracker needs the VBO module */ _vbo_CreateContext(ctx); st->dirty.mesa = ~0; st->dirty.st = ~0; st->uploader = u_upload_create(st->pipe, 65536, 4, PIPE_BIND_VERTEX_BUFFER); if (!screen->get_param(screen, PIPE_CAP_USER_INDEX_BUFFERS)) { st->indexbuf_uploader = u_upload_create(st->pipe, 128 * 1024, 4, PIPE_BIND_INDEX_BUFFER); } if (!screen->get_param(screen, PIPE_CAP_USER_CONSTANT_BUFFERS)) { unsigned alignment = screen->get_param(screen, PIPE_CAP_CONSTANT_BUFFER_OFFSET_ALIGNMENT); st->constbuf_uploader = u_upload_create(pipe, 128 * 1024, alignment, PIPE_BIND_CONSTANT_BUFFER); } st->cso_context = cso_create_context(pipe); st_init_atoms( st ); st_init_bitmap(st); st_init_clear(st); st_init_draw( st ); st_init_generate_mipmap(st); if(pipe->screen->get_param(pipe->screen, PIPE_CAP_NPOT_TEXTURES)) st->internal_target = PIPE_TEXTURE_2D; else st->internal_target = PIPE_TEXTURE_RECT; /* Vertex element objects used for drawing rectangles for glBitmap, * glDrawPixels, glClear, etc. */ for (i = 0; i < Elements(st->velems_util_draw); i++) { memset(&st->velems_util_draw[i], 0, sizeof(struct pipe_vertex_element)); st->velems_util_draw[i].src_offset = i * 4 * sizeof(float); st->velems_util_draw[i].instance_divisor = 0; st->velems_util_draw[i].vertex_buffer_index = cso_get_aux_vertex_buffer_slot(st->cso_context); st->velems_util_draw[i].src_format = PIPE_FORMAT_R32G32B32A32_FLOAT; } /* we want all vertex data to be placed in buffer objects */ vbo_use_buffer_objects(ctx); /* make sure that no VBOs are left mapped when we're drawing. */ vbo_always_unmap_buffers(ctx); /* Need these flags: */ st->ctx->FragmentProgram._MaintainTexEnvProgram = GL_TRUE; st->ctx->VertexProgram._MaintainTnlProgram = GL_TRUE; st->pixel_xfer.cache = _mesa_new_program_cache(); st->has_stencil_export = screen->get_param(screen, PIPE_CAP_SHADER_STENCIL_EXPORT); st->has_shader_model3 = screen->get_param(screen, PIPE_CAP_SM3); /* GL limits and extensions */ st_init_limits(st); st_init_extensions(st); _mesa_compute_version(ctx); _mesa_initialize_dispatch_tables(ctx); _mesa_initialize_vbo_vtxfmt(ctx); return st; }
/* Setup all vertex pipeline state, rasterizer state, and fragment shader * constants, and issue the draw call for PBO upload/download. * * The caller is responsible for saving and restoring state, as well as for * setting other fragment shader state (fragment shader, samplers), and * framebuffer/viewport/DSA/blend state. */ bool st_pbo_draw(struct st_context *st, const struct st_pbo_addresses *addr, unsigned surface_width, unsigned surface_height) { struct cso_context *cso = st->cso_context; /* Setup vertex and geometry shaders */ if (!st->pbo.vs) { st->pbo.vs = st_pbo_create_vs(st); if (!st->pbo.vs) return false; } if (addr->depth != 1 && st->pbo.use_gs && !st->pbo.gs) { st->pbo.gs = st_pbo_create_gs(st); if (!st->pbo.gs) return false; } cso_set_vertex_shader_handle(cso, st->pbo.vs); cso_set_geometry_shader_handle(cso, addr->depth != 1 ? st->pbo.gs : NULL); cso_set_tessctrl_shader_handle(cso, NULL); cso_set_tesseval_shader_handle(cso, NULL); /* Upload vertices */ { struct pipe_vertex_buffer vbo; struct pipe_vertex_element velem; float x0 = (float) addr->xoffset / surface_width * 2.0f - 1.0f; float y0 = (float) addr->yoffset / surface_height * 2.0f - 1.0f; float x1 = (float) (addr->xoffset + addr->width) / surface_width * 2.0f - 1.0f; float y1 = (float) (addr->yoffset + addr->height) / surface_height * 2.0f - 1.0f; float *verts = NULL; vbo.user_buffer = NULL; vbo.buffer = NULL; vbo.stride = 2 * sizeof(float); u_upload_alloc(st->uploader, 0, 8 * sizeof(float), 4, &vbo.buffer_offset, &vbo.buffer, (void **) &verts); if (!verts) return false; verts[0] = x0; verts[1] = y0; verts[2] = x0; verts[3] = y1; verts[4] = x1; verts[5] = y0; verts[6] = x1; verts[7] = y1; u_upload_unmap(st->uploader); velem.src_offset = 0; velem.instance_divisor = 0; velem.vertex_buffer_index = cso_get_aux_vertex_buffer_slot(cso); velem.src_format = PIPE_FORMAT_R32G32_FLOAT; cso_set_vertex_elements(cso, 1, &velem); cso_set_vertex_buffers(cso, velem.vertex_buffer_index, 1, &vbo); pipe_resource_reference(&vbo.buffer, NULL); } /* Upload constants */ { struct pipe_constant_buffer cb; if (st->constbuf_uploader) { cb.buffer = NULL; cb.user_buffer = NULL; u_upload_data(st->constbuf_uploader, 0, sizeof(addr->constants), st->ctx->Const.UniformBufferOffsetAlignment, &addr->constants, &cb.buffer_offset, &cb.buffer); if (!cb.buffer) return false; u_upload_unmap(st->constbuf_uploader); } else { cb.buffer = NULL; cb.user_buffer = &addr->constants; cb.buffer_offset = 0; } cb.buffer_size = sizeof(addr->constants); cso_set_constant_buffer(cso, PIPE_SHADER_FRAGMENT, 0, &cb); pipe_resource_reference(&cb.buffer, NULL); } /* Rasterizer state */ cso_set_rasterizer(cso, &st->pbo.raster); /* Disable stream output */ cso_set_stream_outputs(cso, 0, NULL, 0); if (addr->depth == 1) { cso_draw_arrays(cso, PIPE_PRIM_TRIANGLE_STRIP, 0, 4); } else { cso_draw_arrays_instanced(cso, PIPE_PRIM_TRIANGLE_STRIP, 0, 4, 0, addr->depth); } return true; }
/** * Copy pixel block from src sampler view to dst surface. * * The sampler view's first_level field indicates the source * mipmap level to use. * * The sampler view's first_layer indicate the layer to use, but for * cube maps it must point to the first face. Face is passed in src_face. * * The main advantage over util_blit_pixels is that it allows to specify swizzles in * pipe_sampler_view::swizzle_?. * * But there is no control over blitting Z and/or stencil. */ void util_blit_pixels_tex(struct blit_state *ctx, struct pipe_sampler_view *src_sampler_view, int srcX0, int srcY0, int srcX1, int srcY1, unsigned src_face, struct pipe_surface *dst, int dstX0, int dstY0, int dstX1, int dstY1, float z, uint filter) { boolean normalized = src_sampler_view->texture->target != PIPE_TEXTURE_RECT; struct pipe_framebuffer_state fb; float s0, t0, s1, t1; unsigned offset; struct pipe_resource *tex = src_sampler_view->texture; assert(filter == PIPE_TEX_MIPFILTER_NEAREST || filter == PIPE_TEX_MIPFILTER_LINEAR); assert(tex); assert(tex->width0 != 0); assert(tex->height0 != 0); s0 = (float) srcX0; s1 = (float) srcX1; t0 = (float) srcY0; t1 = (float) srcY1; if(normalized) { /* normalize according to the mipmap level's size */ int level = src_sampler_view->u.tex.first_level; float w = (float) u_minify(tex->width0, level); float h = (float) u_minify(tex->height0, level); s0 /= w; s1 /= w; t0 /= h; t1 /= h; } assert(ctx->pipe->screen->is_format_supported(ctx->pipe->screen, dst->format, PIPE_TEXTURE_2D, dst->texture->nr_samples, PIPE_BIND_RENDER_TARGET)); /* save state (restored below) */ cso_save_blend(ctx->cso); cso_save_depth_stencil_alpha(ctx->cso); cso_save_rasterizer(ctx->cso); cso_save_sample_mask(ctx->cso); cso_save_samplers(ctx->cso, PIPE_SHADER_FRAGMENT); cso_save_sampler_views(ctx->cso, PIPE_SHADER_FRAGMENT); cso_save_stream_outputs(ctx->cso); cso_save_viewport(ctx->cso); cso_save_framebuffer(ctx->cso); cso_save_fragment_shader(ctx->cso); cso_save_vertex_shader(ctx->cso); cso_save_geometry_shader(ctx->cso); cso_save_vertex_elements(ctx->cso); cso_save_aux_vertex_buffer_slot(ctx->cso); /* set misc state we care about */ cso_set_blend(ctx->cso, &ctx->blend_write_color); cso_set_depth_stencil_alpha(ctx->cso, &ctx->dsa_keep_depthstencil); cso_set_sample_mask(ctx->cso, ~0); cso_set_rasterizer(ctx->cso, &ctx->rasterizer); cso_set_vertex_elements(ctx->cso, 2, ctx->velem); cso_set_stream_outputs(ctx->cso, 0, NULL, 0); /* sampler */ ctx->sampler.normalized_coords = normalized; ctx->sampler.min_img_filter = filter; ctx->sampler.mag_img_filter = filter; cso_single_sampler(ctx->cso, PIPE_SHADER_FRAGMENT, 0, &ctx->sampler); cso_single_sampler_done(ctx->cso, PIPE_SHADER_FRAGMENT); /* viewport */ ctx->viewport.scale[0] = 0.5f * dst->width; ctx->viewport.scale[1] = 0.5f * dst->height; ctx->viewport.scale[2] = 0.5f; ctx->viewport.scale[3] = 1.0f; ctx->viewport.translate[0] = 0.5f * dst->width; ctx->viewport.translate[1] = 0.5f * dst->height; ctx->viewport.translate[2] = 0.5f; ctx->viewport.translate[3] = 0.0f; cso_set_viewport(ctx->cso, &ctx->viewport); /* texture */ cso_set_sampler_views(ctx->cso, PIPE_SHADER_FRAGMENT, 1, &src_sampler_view); /* shaders */ set_fragment_shader(ctx, TGSI_WRITEMASK_XYZW, src_sampler_view->texture->target); set_vertex_shader(ctx); cso_set_geometry_shader_handle(ctx->cso, NULL); /* drawing dest */ memset(&fb, 0, sizeof(fb)); fb.width = dst->width; fb.height = dst->height; fb.nr_cbufs = 1; fb.cbufs[0] = dst; cso_set_framebuffer(ctx->cso, &fb); /* draw quad */ offset = setup_vertex_data_tex(ctx, src_sampler_view->texture->target, src_face, (float) dstX0 / dst->width * 2.0f - 1.0f, (float) dstY0 / dst->height * 2.0f - 1.0f, (float) dstX1 / dst->width * 2.0f - 1.0f, (float) dstY1 / dst->height * 2.0f - 1.0f, s0, t0, s1, t1, z); util_draw_vertex_buffer(ctx->pipe, ctx->cso, ctx->vbuf, cso_get_aux_vertex_buffer_slot(ctx->cso), offset, PIPE_PRIM_TRIANGLE_FAN, 4, /* verts */ 2); /* attribs/vert */ /* restore state we changed */ cso_restore_blend(ctx->cso); cso_restore_depth_stencil_alpha(ctx->cso); cso_restore_rasterizer(ctx->cso); cso_restore_sample_mask(ctx->cso); cso_restore_samplers(ctx->cso, PIPE_SHADER_FRAGMENT); cso_restore_sampler_views(ctx->cso, PIPE_SHADER_FRAGMENT); cso_restore_viewport(ctx->cso); cso_restore_framebuffer(ctx->cso); cso_restore_fragment_shader(ctx->cso); cso_restore_vertex_shader(ctx->cso); cso_restore_geometry_shader(ctx->cso); cso_restore_vertex_elements(ctx->cso); cso_restore_aux_vertex_buffer_slot(ctx->cso); cso_restore_stream_outputs(ctx->cso); }
/** * Render a glBitmap by drawing a textured quad */ static void draw_bitmap_quad(struct gl_context *ctx, GLint x, GLint y, GLfloat z, GLsizei width, GLsizei height, struct pipe_sampler_view *sv, const GLfloat *color) { struct st_context *st = st_context(ctx); struct pipe_context *pipe = st->pipe; struct cso_context *cso = st->cso_context; struct st_fp_variant *fpv; struct st_fp_variant_key key; GLuint maxSize; GLuint offset; struct pipe_resource *vbuf = NULL; memset(&key, 0, sizeof(key)); key.st = st; key.bitmap = GL_TRUE; key.clamp_color = st->clamp_frag_color_in_shader && st->ctx->Color._ClampFragmentColor && !st->ctx->DrawBuffer->_IntegerColor; fpv = st_get_fp_variant(st, st->fp, &key); /* As an optimization, Mesa's fragment programs will sometimes get the * primary color from a statevar/constant rather than a varying variable. * when that's the case, we need to ensure that we use the 'color' * parameter and not the current attribute color (which may have changed * through glRasterPos and state validation. * So, we force the proper color here. Not elegant, but it works. */ { GLfloat colorSave[4]; COPY_4V(colorSave, ctx->Current.Attrib[VERT_ATTRIB_COLOR0]); COPY_4V(ctx->Current.Attrib[VERT_ATTRIB_COLOR0], color); st_upload_constants(st, fpv->parameters, PIPE_SHADER_FRAGMENT); COPY_4V(ctx->Current.Attrib[VERT_ATTRIB_COLOR0], colorSave); } /* limit checks */ /* XXX if the bitmap is larger than the max texture size, break * it up into chunks. */ maxSize = 1 << (pipe->screen->get_param(pipe->screen, PIPE_CAP_MAX_TEXTURE_2D_LEVELS) - 1); assert(width <= (GLsizei)maxSize); assert(height <= (GLsizei)maxSize); cso_save_rasterizer(cso); cso_save_samplers(cso, PIPE_SHADER_FRAGMENT); cso_save_sampler_views(cso, PIPE_SHADER_FRAGMENT); cso_save_viewport(cso); cso_save_fragment_shader(cso); cso_save_stream_outputs(cso); cso_save_vertex_shader(cso); cso_save_geometry_shader(cso); cso_save_vertex_elements(cso); cso_save_aux_vertex_buffer_slot(cso); /* rasterizer state: just scissor */ st->bitmap.rasterizer.scissor = ctx->Scissor.Enabled; cso_set_rasterizer(cso, &st->bitmap.rasterizer); /* fragment shader state: TEX lookup program */ cso_set_fragment_shader_handle(cso, fpv->driver_shader); /* vertex shader state: position + texcoord pass-through */ cso_set_vertex_shader_handle(cso, st->bitmap.vs); /* geometry shader state: disabled */ cso_set_geometry_shader_handle(cso, NULL); /* user samplers, plus our bitmap sampler */ { struct pipe_sampler_state *samplers[PIPE_MAX_SAMPLERS]; uint num = MAX2(fpv->bitmap_sampler + 1, st->state.num_samplers[PIPE_SHADER_FRAGMENT]); uint i; for (i = 0; i < st->state.num_samplers[PIPE_SHADER_FRAGMENT]; i++) { samplers[i] = &st->state.samplers[PIPE_SHADER_FRAGMENT][i]; } samplers[fpv->bitmap_sampler] = &st->bitmap.samplers[sv->texture->target != PIPE_TEXTURE_RECT]; cso_set_samplers(cso, PIPE_SHADER_FRAGMENT, num, (const struct pipe_sampler_state **) samplers); } /* user textures, plus the bitmap texture */ { struct pipe_sampler_view *sampler_views[PIPE_MAX_SAMPLERS]; uint num = MAX2(fpv->bitmap_sampler + 1, st->state.num_sampler_views[PIPE_SHADER_FRAGMENT]); memcpy(sampler_views, st->state.sampler_views[PIPE_SHADER_FRAGMENT], sizeof(sampler_views)); sampler_views[fpv->bitmap_sampler] = sv; cso_set_sampler_views(cso, PIPE_SHADER_FRAGMENT, num, sampler_views); } /* viewport state: viewport matching window dims */ { const GLboolean invert = st->state.fb_orientation == Y_0_TOP; const GLfloat width = (GLfloat)st->state.framebuffer.width; const GLfloat height = (GLfloat)st->state.framebuffer.height; struct pipe_viewport_state vp; vp.scale[0] = 0.5f * width; vp.scale[1] = height * (invert ? -0.5f : 0.5f); vp.scale[2] = 0.5f; vp.scale[3] = 1.0f; vp.translate[0] = 0.5f * width; vp.translate[1] = 0.5f * height; vp.translate[2] = 0.5f; vp.translate[3] = 0.0f; cso_set_viewport(cso, &vp); } cso_set_vertex_elements(cso, 3, st->velems_util_draw); cso_set_stream_outputs(st->cso_context, 0, NULL, 0); /* convert Z from [0,1] to [-1,-1] to match viewport Z scale/bias */ z = z * 2.0f - 1.0f; /* draw textured quad */ setup_bitmap_vertex_data(st, sv->texture->target != PIPE_TEXTURE_RECT, x, y, width, height, z, color, &vbuf, &offset); if (vbuf) { util_draw_vertex_buffer(pipe, st->cso_context, vbuf, cso_get_aux_vertex_buffer_slot(st->cso_context), offset, PIPE_PRIM_TRIANGLE_FAN, 4, /* verts */ 3); /* attribs/vert */ } /* restore state */ cso_restore_rasterizer(cso); cso_restore_samplers(cso, PIPE_SHADER_FRAGMENT); cso_restore_sampler_views(cso, PIPE_SHADER_FRAGMENT); cso_restore_viewport(cso); cso_restore_fragment_shader(cso); cso_restore_vertex_shader(cso); cso_restore_geometry_shader(cso); cso_restore_vertex_elements(cso); cso_restore_aux_vertex_buffer_slot(cso); cso_restore_stream_outputs(cso); pipe_resource_reference(&vbuf, NULL); }