+/**
+ * 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.tex_format) {
+ 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 = util_ifloor(ctx->Current.RasterPos[0] - xorig + epsilon);
+ const float y0 = util_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, 0, 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;
+}
+
+
+