/** * 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 */ }
/** * Scissor depends on the scissor box, and the framebuffer dimensions. */ static void update_scissor( struct st_context *st ) { struct pipe_scissor_state scissor; const struct gl_framebuffer *fb = st->ctx->DrawBuffer; GLint miny, maxy; scissor.minx = 0; scissor.miny = 0; scissor.maxx = fb->Width; scissor.maxy = fb->Height; if (st->ctx->Scissor.Enabled) { /* need to be careful here with xmax or ymax < 0 */ GLint xmax = MAX2(0, st->ctx->Scissor.X + st->ctx->Scissor.Width); GLint ymax = MAX2(0, st->ctx->Scissor.Y + st->ctx->Scissor.Height); if (st->ctx->Scissor.X > (GLint)scissor.minx) scissor.minx = st->ctx->Scissor.X; if (st->ctx->Scissor.Y > (GLint)scissor.miny) scissor.miny = st->ctx->Scissor.Y; if (xmax < (GLint) scissor.maxx) scissor.maxx = xmax; if (ymax < (GLint) scissor.maxy) scissor.maxy = ymax; /* check for null space */ if (scissor.minx >= scissor.maxx || scissor.miny >= scissor.maxy) scissor.minx = scissor.miny = scissor.maxx = scissor.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.maxy; maxy = fb->Height - scissor.miny; scissor.miny = miny; scissor.maxy = maxy; } if (memcmp(&scissor, &st->state.scissor, sizeof(scissor)) != 0) { /* state has changed */ st->state.scissor = scissor; /* struct copy */ st->pipe->set_scissor_state(st->pipe, &scissor); /* activate */ } }
/** * Normally, this function would render a GL_POINT. */ static void rastpos_point(struct draw_stage *stage, struct prim_header *prim) { struct rastpos_stage *rs = rastpos_stage(stage); struct gl_context *ctx = rs->ctx; struct st_context *st = st_context(ctx); const GLfloat height = (GLfloat) ctx->DrawBuffer->Height; const GLuint *outputMapping = st->vertex_result_to_slot; const GLfloat *pos; GLuint i; /* if we get here, we didn't get clipped */ ctx->Current.RasterPosValid = GL_TRUE; /* update raster pos */ pos = prim->v[0]->data[0]; ctx->Current.RasterPos[0] = pos[0]; if (st_fb_orientation(ctx->DrawBuffer) == Y_0_TOP) ctx->Current.RasterPos[1] = height - pos[1]; /* invert Y */ else ctx->Current.RasterPos[1] = pos[1]; ctx->Current.RasterPos[2] = pos[2]; ctx->Current.RasterPos[3] = pos[3]; /* update other raster attribs */ update_attrib(ctx, outputMapping, prim->v[0], ctx->Current.RasterColor, VARYING_SLOT_COL0, VERT_ATTRIB_COLOR0); update_attrib(ctx, outputMapping, prim->v[0], ctx->Current.RasterSecondaryColor, VARYING_SLOT_COL1, VERT_ATTRIB_COLOR1); for (i = 0; i < ctx->Const.MaxTextureCoordUnits; i++) { update_attrib(ctx, outputMapping, prim->v[0], ctx->Current.RasterTexCoords[i], VARYING_SLOT_TEX0 + i, VERT_ATTRIB_TEX0 + i); } if (ctx->RenderMode == GL_SELECT) { _mesa_update_hitflag( ctx, ctx->Current.RasterPos[2] ); } }
/** * Update the viewport transformation matrix. Depends on: * - viewport pos/size * - depthrange * - window pos/size or FBO size */ static void update_viewport( struct st_context *st ) { struct gl_context *ctx = st->ctx; GLfloat yScale, yBias; int i; /* _NEW_BUFFERS */ if (st_fb_orientation(ctx->DrawBuffer) == Y_0_TOP) { /* Drawing to a window. The corresponding gallium surface uses * Y=0=TOP but OpenGL is Y=0=BOTTOM. So we need to invert the viewport. */ yScale = -1; yBias = (GLfloat)ctx->DrawBuffer->Height; } else { /* Drawing to an FBO where Y=0=BOTTOM, like OpenGL - don't invert */ yScale = 1.0; yBias = 0.0; } /* _NEW_VIEWPORT */ for (i = 0; i < ctx->Const.MaxViewports; i++) { double scale[3], translate[3]; _mesa_get_viewport_xform(ctx, i, scale, translate); st->state.viewport[i].scale[0] = scale[0]; st->state.viewport[i].scale[1] = scale[1] * yScale; st->state.viewport[i].scale[2] = scale[2]; st->state.viewport[i].scale[3] = 1.0; st->state.viewport[i].translate[0] = translate[0]; st->state.viewport[i].translate[1] = translate[1] * yScale + yBias; st->state.viewport[i].translate[2] = translate[2]; st->state.viewport[i].translate[3] = 0.0; } cso_set_viewport(st->cso_context, &st->state.viewport[0]); if (ctx->Const.MaxViewports > 1) st->pipe->set_viewport_states(st->pipe, 1, ctx->Const.MaxViewports - 1, &st->state.viewport[1]); }
/** * Update the viewport transformation matrix. Depends on: * - viewport pos/size * - depthrange * - window pos/size or FBO size */ static void update_viewport( struct st_context *st ) { GLcontext *ctx = st->ctx; GLfloat yScale, yBias; /* _NEW_BUFFERS */ if (st_fb_orientation(ctx->DrawBuffer) == Y_0_TOP) { yScale = -1; yBias = (GLfloat)ctx->DrawBuffer->Height; } else { yScale = 1.0; yBias = 0.0; } /* _NEW_VIEWPORT */ { GLfloat x = (GLfloat)ctx->Viewport.X; GLfloat y = (GLfloat)ctx->Viewport.Y; GLfloat z = ctx->Viewport.Near; GLfloat half_width = (GLfloat)ctx->Viewport.Width * 0.5f; GLfloat half_height = (GLfloat)ctx->Viewport.Height * 0.5f; GLfloat half_depth = (GLfloat)(ctx->Viewport.Far - ctx->Viewport.Near) * 0.5f; st->state.viewport.scale[0] = half_width; st->state.viewport.scale[1] = half_height * yScale; st->state.viewport.scale[2] = half_depth; st->state.viewport.scale[3] = 1.0; st->state.viewport.translate[0] = half_width + x; st->state.viewport.translate[1] = (half_height + y) * yScale + yBias; st->state.viewport.translate[2] = half_depth + z; st->state.viewport.translate[3] = 0.0; cso_set_viewport(st->cso_context, &st->state.viewport); } }
static void st_BlitFramebuffer(GLcontext *ctx, GLint srcX0, GLint srcY0, GLint srcX1, GLint srcY1, GLint dstX0, GLint dstY0, GLint dstX1, GLint dstY1, GLbitfield mask, GLenum filter) { struct st_context *st = ctx->st; const uint pFilter = ((filter == GL_NEAREST) ? PIPE_TEX_MIPFILTER_NEAREST : PIPE_TEX_MIPFILTER_LINEAR); if (mask & GL_COLOR_BUFFER_BIT) { struct st_renderbuffer *srcRb = st_renderbuffer(ctx->ReadBuffer->_ColorReadBuffer); struct st_renderbuffer *dstRb = st_renderbuffer(ctx->DrawBuffer->_ColorDrawBuffers[0][0]); struct pipe_surface *srcSurf = srcRb->surface; struct pipe_surface *dstSurf = dstRb->surface; if (st_fb_orientation(ctx->DrawBuffer) == Y_0_TOP) { /* invert Y */ srcY0 = srcRb->Base.Height - srcY0; srcY1 = srcRb->Base.Height - srcY1; dstY0 = dstRb->Base.Height - dstY0; dstY1 = dstRb->Base.Height - dstY1; } util_blit_pixels(st->blit, srcSurf, srcX0, srcY0, srcX1, srcY1, dstSurf, dstX0, dstY0, dstX1, dstY1, 0.0, pFilter); } }
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); }
/** * Do a CopyTex[Sub]Image1/2/3D() using a hardware (blit) path if possible. * Note that the region to copy has already been clipped so we know we * won't read from outside the source renderbuffer's bounds. * * Note: srcY=0=Bottom of renderbuffer (GL convention) */ static void st_CopyTexSubImage(struct gl_context *ctx, GLuint dims, struct gl_texture_image *texImage, GLint destX, GLint destY, GLint destZ, struct gl_renderbuffer *rb, GLint srcX, GLint srcY, GLsizei width, GLsizei height) { struct st_texture_image *stImage = st_texture_image(texImage); const GLenum texBaseFormat = texImage->_BaseFormat; struct st_renderbuffer *strb = st_renderbuffer(rb); struct st_context *st = st_context(ctx); struct pipe_context *pipe = st->pipe; struct pipe_screen *screen = pipe->screen; enum pipe_format dest_format, src_format; GLboolean matching_base_formats; GLuint color_writemask, zs_writemask, sample_count; struct pipe_surface *dest_surface = NULL; GLboolean do_flip = (st_fb_orientation(ctx->ReadBuffer) == Y_0_TOP); struct pipe_surface surf_tmpl; unsigned int dst_usage; GLint srcY0, srcY1; /* make sure finalize_textures has been called? */ if (0) st_validate_state(st); if (!strb || !strb->surface || !stImage->pt) { debug_printf("%s: null strb or stImage\n", __FUNCTION__); return; } sample_count = strb->surface->texture->nr_samples; /* I believe this would be legal, presumably would need to do a resolve for color, and for depth/stencil spec says to just use one of the depth/stencil samples per pixel? Need some transfer clarifications. */ assert(sample_count < 2); assert(strb); assert(strb->surface); assert(stImage->pt); src_format = strb->surface->format; dest_format = stImage->pt->format; /* * Determine if the src framebuffer and dest texture have the same * base format. We need this to detect a case such as the framebuffer * being GL_RGBA but the texture being GL_RGB. If the actual hardware * texture format stores RGBA we need to set A=1 (overriding the * framebuffer's alpha values). We can't do that with the blit or * textured-quad paths. */ matching_base_formats = (_mesa_get_format_base_format(strb->Base.Format) == _mesa_get_format_base_format(texImage->TexFormat)); if (ctx->_ImageTransferState) { goto fallback; } if (texImage->TexObject->Target == GL_TEXTURE_1D_ARRAY) { /* 1D arrays might be thought of as 2D images but the actual layout * might not be that way. At some points, we convert OpenGL's 1D * array 'height' into gallium 'layers' and that prevents the blit * utility code from doing the right thing. Simpy use the memcpy-based * fallback. */ goto fallback; } if (matching_base_formats && src_format == dest_format && !do_flip) { /* use surface_copy() / blit */ struct pipe_box src_box; unsigned dstLevel; u_box_2d_zslice(srcX, srcY, strb->surface->u.tex.first_layer, width, height, &src_box); /* If stImage->pt is an independent image (not a pointer into a full * mipmap) stImage->pt.last_level will be zero and we need to use that * as the dest level. */ dstLevel = MIN2(stImage->base.Level, stImage->pt->last_level); /* for resource_copy_region(), y=0=top, always */ pipe->resource_copy_region(pipe, /* dest */ stImage->pt, dstLevel, destX, destY, destZ + stImage->base.Face, /* src */ strb->texture, strb->surface->u.tex.level, &src_box); return; } if (texBaseFormat == GL_DEPTH_STENCIL) { goto fallback; } if (texBaseFormat == GL_DEPTH_COMPONENT) { color_writemask = 0; zs_writemask = BLIT_WRITEMASK_Z; dst_usage = PIPE_BIND_DEPTH_STENCIL; } else { color_writemask = compatible_src_dst_formats(ctx, &strb->Base, texImage); zs_writemask = 0; dst_usage = PIPE_BIND_RENDER_TARGET; } if ((!color_writemask && !zs_writemask) || !screen->is_format_supported(screen, src_format, PIPE_TEXTURE_2D, sample_count, PIPE_BIND_SAMPLER_VIEW) || !screen->is_format_supported(screen, dest_format, PIPE_TEXTURE_2D, 0, dst_usage)) { goto fallback; } if (do_flip) { srcY1 = strb->Base.Height - srcY - height; srcY0 = srcY1 + height; } else { srcY0 = srcY; srcY1 = srcY0 + height; } /* Disable conditional rendering. */ if (st->render_condition) { pipe->render_condition(pipe, NULL, 0); } memset(&surf_tmpl, 0, sizeof(surf_tmpl)); surf_tmpl.format = util_format_linear(stImage->pt->format); surf_tmpl.usage = dst_usage; surf_tmpl.u.tex.level = stImage->base.Level; surf_tmpl.u.tex.first_layer = stImage->base.Face + destZ; surf_tmpl.u.tex.last_layer = stImage->base.Face + destZ; dest_surface = pipe->create_surface(pipe, stImage->pt, &surf_tmpl); util_blit_pixels(st->blit, strb->texture, strb->surface->u.tex.level, srcX, srcY0, srcX + width, srcY1, strb->surface->u.tex.first_layer, dest_surface, destX, destY, destX + width, destY + height, 0.0, PIPE_TEX_MIPFILTER_NEAREST, color_writemask, zs_writemask); pipe_surface_reference(&dest_surface, NULL); /* Restore conditional rendering state. */ if (st->render_condition) { pipe->render_condition(pipe, st->render_condition, st->condition_mode); } return; fallback: /* software fallback */ fallback_copy_texsubimage(ctx, strb, stImage, texBaseFormat, destX, destY, destZ, srcX, srcY, width, height); }
static void st_BlitFramebuffer(GLcontext *ctx, GLint srcX0, GLint srcY0, GLint srcX1, GLint srcY1, GLint dstX0, GLint dstY0, GLint dstX1, GLint dstY1, GLbitfield mask, GLenum filter) { const GLbitfield depthStencil = (GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT); struct st_context *st = st_context(ctx); const uint pFilter = ((filter == GL_NEAREST) ? PIPE_TEX_MIPFILTER_NEAREST : PIPE_TEX_MIPFILTER_LINEAR); struct gl_framebuffer *readFB = ctx->ReadBuffer; struct gl_framebuffer *drawFB = ctx->DrawBuffer; if (!_mesa_clip_blit(ctx, &srcX0, &srcY0, &srcX1, &srcY1, &dstX0, &dstY0, &dstX1, &dstY1)) { return; /* nothing to draw/blit */ } if (st_fb_orientation(drawFB) == Y_0_TOP) { /* invert Y for dest */ dstY0 = drawFB->Height - dstY0; dstY1 = drawFB->Height - dstY1; } if (st_fb_orientation(readFB) == Y_0_TOP) { /* invert Y for src */ srcY0 = readFB->Height - srcY0; srcY1 = readFB->Height - srcY1; } if (srcY0 > srcY1 && dstY0 > dstY1) { /* Both src and dst are upside down. Swap Y to make it * right-side up to increase odds of using a fast path. * Recall that all Gallium raster coords have Y=0=top. */ GLint tmp; tmp = srcY0; srcY0 = srcY1; srcY1 = tmp; tmp = dstY0; dstY0 = dstY1; dstY1 = tmp; } if (mask & GL_COLOR_BUFFER_BIT) { struct gl_renderbuffer_attachment *srcAtt = &readFB->Attachment[readFB->_ColorReadBufferIndex]; if(srcAtt->Type == GL_TEXTURE) { struct st_texture_object *srcObj = st_texture_object(srcAtt->Texture); struct st_renderbuffer *dstRb = st_renderbuffer(drawFB->_ColorDrawBuffers[0]); struct pipe_subresource srcSub; struct pipe_surface *dstSurf = dstRb->surface; if (!srcObj->pt) return; srcSub.face = srcAtt->CubeMapFace; srcSub.level = srcAtt->TextureLevel; util_blit_pixels(st->blit, srcObj->pt, srcSub, srcX0, srcY0, srcX1, srcY1, srcAtt->Zoffset, dstSurf, dstX0, dstY0, dstX1, dstY1, 0.0, pFilter); } else { struct st_renderbuffer *srcRb = st_renderbuffer(readFB->_ColorReadBuffer); struct st_renderbuffer *dstRb = st_renderbuffer(drawFB->_ColorDrawBuffers[0]); struct pipe_surface *srcSurf = srcRb->surface; struct pipe_surface *dstSurf = dstRb->surface; struct pipe_subresource srcSub; srcSub.face = srcSurf->face; srcSub.level = srcSurf->level; util_blit_pixels(st->blit, srcRb->texture, srcSub, srcX0, srcY0, srcX1, srcY1, srcSurf->zslice, dstSurf, dstX0, dstY0, dstX1, dstY1, 0.0, pFilter); } } if (mask & depthStencil) { /* depth and/or stencil blit */ /* get src/dst depth surfaces */ struct gl_renderbuffer_attachment *srcDepth = &readFB->Attachment[BUFFER_DEPTH]; struct gl_renderbuffer_attachment *dstDepth = &drawFB->Attachment[BUFFER_DEPTH]; struct gl_renderbuffer_attachment *srcStencil = &readFB->Attachment[BUFFER_STENCIL]; struct gl_renderbuffer_attachment *dstStencil = &drawFB->Attachment[BUFFER_STENCIL]; struct st_renderbuffer *srcDepthRb = st_renderbuffer(readFB->Attachment[BUFFER_DEPTH].Renderbuffer); struct st_renderbuffer *dstDepthRb = st_renderbuffer(drawFB->Attachment[BUFFER_DEPTH].Renderbuffer); struct pipe_surface *dstDepthSurf = dstDepthRb ? dstDepthRb->surface : NULL; if ((mask & depthStencil) == depthStencil && st_is_depth_stencil_combined(srcDepth, srcStencil) && st_is_depth_stencil_combined(dstDepth, dstStencil)) { /* Blitting depth and stencil values between combined * depth/stencil buffers. This is the ideal case for such buffers. */ util_blit_pixels(st->blit, srcDepthRb->texture, u_subresource(srcDepthRb->surface->face, srcDepthRb->surface->level), srcX0, srcY0, srcX1, srcY1, srcDepthRb->surface->zslice, dstDepthSurf, dstX0, dstY0, dstX1, dstY1, 0.0, pFilter); } else { /* blitting depth and stencil separately */ if (mask & GL_DEPTH_BUFFER_BIT) { util_blit_pixels(st->blit, srcDepthRb->texture, u_subresource(srcDepthRb->surface->face, srcDepthRb->surface->level), srcX0, srcY0, srcX1, srcY1, srcDepthRb->surface->zslice, dstDepthSurf, dstX0, dstY0, dstX1, dstY1, 0.0, pFilter); } if (mask & GL_STENCIL_BUFFER_BIT) { /* blit stencil only */ _mesa_problem(ctx, "st_BlitFramebuffer(STENCIL) not completed"); } } } }
/** * 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; memset(&key, 0, sizeof(key)); key.st = st; key.bitmap = GL_TRUE; 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); cso_save_fragment_sampler_views(cso); cso_save_viewport(cso); cso_save_fragment_shader(cso); cso_save_vertex_shader(cso); cso_save_vertex_elements(cso); cso_save_vertex_buffers(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); /* 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); uint i; for (i = 0; i < st->state.num_samplers; i++) { samplers[i] = &st->state.samplers[i]; } samplers[fpv->bitmap_sampler] = &st->bitmap.samplers[sv->texture->target != PIPE_TEXTURE_RECT]; cso_set_samplers(cso, 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_textures); memcpy(sampler_views, st->state.sampler_views, sizeof(sampler_views)); sampler_views[fpv->bitmap_sampler] = sv; cso_set_fragment_sampler_views(cso, num, sampler_views); } /* viewport state: viewport matching window dims */ { const struct gl_framebuffer *fb = st->ctx->DrawBuffer; const GLboolean invert = (st_fb_orientation(fb) == Y_0_TOP); const GLfloat width = (GLfloat)fb->Width; const GLfloat height = (GLfloat)fb->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); /* convert Z from [0,1] to [-1,-1] to match viewport Z scale/bias */ z = z * 2.0 - 1.0; /* draw textured quad */ offset = setup_bitmap_vertex_data(st, sv->texture->target != PIPE_TEXTURE_RECT, x, y, width, height, z, color); util_draw_vertex_buffer(pipe, st->cso_context, st->bitmap.vbuf, offset, PIPE_PRIM_TRIANGLE_FAN, 4, /* verts */ 3); /* attribs/vert */ /* restore state */ cso_restore_rasterizer(cso); cso_restore_samplers(cso); cso_restore_fragment_sampler_views(cso); cso_restore_viewport(cso); cso_restore_fragment_shader(cso); cso_restore_vertex_shader(cso); cso_restore_vertex_elements(cso); cso_restore_vertex_buffers(cso); }
static void st_BlitFramebuffer(GLcontext *ctx, GLint srcX0, GLint srcY0, GLint srcX1, GLint srcY1, GLint dstX0, GLint dstY0, GLint dstX1, GLint dstY1, GLbitfield mask, GLenum filter) { const GLbitfield depthStencil = (GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT); struct st_context *st = ctx->st; const uint pFilter = ((filter == GL_NEAREST) ? PIPE_TEX_MIPFILTER_NEAREST : PIPE_TEX_MIPFILTER_LINEAR); struct gl_framebuffer *readFB = ctx->ReadBuffer; struct gl_framebuffer *drawFB = ctx->DrawBuffer; if (!_mesa_clip_blit(ctx, &srcX0, &srcY0, &srcX1, &srcY1, &dstX0, &dstY0, &dstX1, &dstY1)) { return; /* nothing to draw/blit */ } if (st_fb_orientation(drawFB) == Y_0_TOP) { /* invert Y for dest */ dstY0 = drawFB->Height - dstY0; dstY1 = drawFB->Height - dstY1; } if (st_fb_orientation(readFB) == Y_0_TOP) { /* invert Y for src */ srcY0 = readFB->Height - srcY0; srcY1 = readFB->Height - srcY1; } if (srcY0 > srcY1 && dstY0 > dstY1) { /* Both src and dst are upside down. Swap Y to make it * right-side up to increase odds of using a fast path. * Recall that all Gallium raster coords have Y=0=top. */ GLint tmp; tmp = srcY0; srcY0 = srcY1; srcY1 = tmp; tmp = dstY0; dstY0 = dstY1; dstY1 = tmp; } if (mask & GL_COLOR_BUFFER_BIT) { struct st_renderbuffer *srcRb = st_renderbuffer(readFB->_ColorReadBuffer); struct st_renderbuffer *dstRb = st_renderbuffer(drawFB->_ColorDrawBuffers[0]); struct pipe_surface *srcSurf = srcRb->surface; struct pipe_surface *dstSurf = dstRb->surface; util_blit_pixels(st->blit, srcSurf, srcX0, srcY0, srcX1, srcY1, dstSurf, dstX0, dstY0, dstX1, dstY1, 0.0, pFilter); } if (mask & depthStencil) { /* depth and/or stencil blit */ /* get src/dst depth surfaces */ struct st_renderbuffer *srcDepthRb = st_renderbuffer(readFB->Attachment[BUFFER_DEPTH].Renderbuffer); struct st_renderbuffer *dstDepthRb = st_renderbuffer(drawFB->Attachment[BUFFER_DEPTH].Renderbuffer); struct pipe_surface *srcDepthSurf = srcDepthRb ? srcDepthRb->surface : NULL; struct pipe_surface *dstDepthSurf = dstDepthRb ? dstDepthRb->surface : NULL; /* get src/dst stencil surfaces */ struct st_renderbuffer *srcStencilRb = st_renderbuffer(readFB->Attachment[BUFFER_STENCIL].Renderbuffer); struct st_renderbuffer *dstStencilRb = st_renderbuffer(drawFB->Attachment[BUFFER_STENCIL].Renderbuffer); struct pipe_surface *srcStencilSurf = srcStencilRb ? srcStencilRb->surface : NULL; struct pipe_surface *dstStencilSurf = dstStencilRb ? dstStencilRb->surface : NULL; if ((mask & depthStencil) == depthStencil && srcDepthSurf == srcStencilSurf && dstDepthSurf == dstStencilSurf) { /* Blitting depth and stencil values between combined * depth/stencil buffers. This is the ideal case for such buffers. */ util_blit_pixels(st->blit, srcDepthSurf, srcX0, srcY0, srcX1, srcY1, dstDepthSurf, dstX0, dstY0, dstX1, dstY1, 0.0, pFilter); } else { /* blitting depth and stencil separately */ if (mask & GL_DEPTH_BUFFER_BIT) { /* blit Z only */ _mesa_problem(ctx, "st_BlitFramebuffer(DEPTH) not completed"); } if (mask & GL_STENCIL_BUFFER_BIT) { /* blit stencil only */ _mesa_problem(ctx, "st_BlitFramebuffer(STENCIL) not completed"); } } } }
/** * 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; }
/** * Do a CopyTex[Sub]Image1/2/3D() using a hardware (blit) path if possible. * Note that the region to copy has already been clipped so we know we * won't read from outside the source renderbuffer's bounds. * * Note: srcY=0=Bottom of renderbuffer (GL convention) */ static void st_copy_texsubimage(struct gl_context *ctx, struct gl_texture_image *texImage, GLint destX, GLint destY, GLint destZ, struct gl_renderbuffer *rb, GLint srcX, GLint srcY, GLsizei width, GLsizei height) { struct st_texture_image *stImage = st_texture_image(texImage); const GLenum texBaseFormat = texImage->_BaseFormat; struct gl_framebuffer *fb = ctx->ReadBuffer; struct st_renderbuffer *strb; struct st_context *st = st_context(ctx); struct pipe_context *pipe = st->pipe; struct pipe_screen *screen = pipe->screen; enum pipe_format dest_format, src_format; GLboolean matching_base_formats; GLuint format_writemask, sample_count; struct pipe_surface *dest_surface = NULL; GLboolean do_flip = (st_fb_orientation(ctx->ReadBuffer) == Y_0_TOP); struct pipe_surface surf_tmpl; unsigned int dst_usage; GLint srcY0, srcY1; /* make sure finalize_textures has been called? */ if (0) st_validate_state(st); /* determine if copying depth or color data */ if (texBaseFormat == GL_DEPTH_COMPONENT || texBaseFormat == GL_DEPTH_STENCIL) { strb = st_renderbuffer(fb->Attachment[BUFFER_DEPTH].Renderbuffer); } else { /* texBaseFormat == GL_RGB, GL_RGBA, GL_ALPHA, etc */ strb = st_renderbuffer(fb->_ColorReadBuffer); } if (!strb || !strb->surface || !stImage->pt) { debug_printf("%s: null strb or stImage\n", __FUNCTION__); return; } sample_count = strb->surface->texture->nr_samples; /* I believe this would be legal, presumably would need to do a resolve for color, and for depth/stencil spec says to just use one of the depth/stencil samples per pixel? Need some transfer clarifications. */ assert(sample_count < 2); assert(strb); assert(strb->surface); assert(stImage->pt); src_format = strb->surface->format; dest_format = stImage->pt->format; /* * Determine if the src framebuffer and dest texture have the same * base format. We need this to detect a case such as the framebuffer * being GL_RGBA but the texture being GL_RGB. If the actual hardware * texture format stores RGBA we need to set A=1 (overriding the * framebuffer's alpha values). We can't do that with the blit or * textured-quad paths. */ matching_base_formats = (_mesa_get_format_base_format(strb->Base.Format) == _mesa_get_format_base_format(texImage->TexFormat)); if (ctx->_ImageTransferState) { goto fallback; } if (matching_base_formats && src_format == dest_format && !do_flip) { /* use surface_copy() / blit */ struct pipe_box src_box; u_box_2d_zslice(srcX, srcY, strb->surface->u.tex.first_layer, width, height, &src_box); /* for resource_copy_region(), y=0=top, always */ pipe->resource_copy_region(pipe, /* dest */ stImage->pt, stImage->base.Level, destX, destY, destZ + stImage->base.Face, /* src */ strb->texture, strb->surface->u.tex.level, &src_box); return; } if (texBaseFormat == GL_DEPTH_STENCIL) { goto fallback; } if (texBaseFormat == GL_DEPTH_COMPONENT) { format_writemask = TGSI_WRITEMASK_XYZW; dst_usage = PIPE_BIND_DEPTH_STENCIL; } else { format_writemask = compatible_src_dst_formats(ctx, &strb->Base, texImage); dst_usage = PIPE_BIND_RENDER_TARGET; } if (!format_writemask || !screen->is_format_supported(screen, src_format, PIPE_TEXTURE_2D, sample_count, PIPE_BIND_SAMPLER_VIEW) || !screen->is_format_supported(screen, dest_format, PIPE_TEXTURE_2D, 0, dst_usage)) { goto fallback; } if (do_flip) { srcY1 = strb->Base.Height - srcY - height; srcY0 = srcY1 + height; } else { srcY0 = srcY; srcY1 = srcY0 + height; } /* Disable conditional rendering. */ if (st->render_condition) { pipe->render_condition(pipe, NULL, 0); } memset(&surf_tmpl, 0, sizeof(surf_tmpl)); surf_tmpl.format = util_format_linear(stImage->pt->format); surf_tmpl.usage = dst_usage; surf_tmpl.u.tex.level = stImage->base.Level; surf_tmpl.u.tex.first_layer = stImage->base.Face + destZ; surf_tmpl.u.tex.last_layer = stImage->base.Face + destZ; dest_surface = pipe->create_surface(pipe, stImage->pt, &surf_tmpl); util_blit_pixels_writemask(st->blit, strb->texture, strb->surface->u.tex.level, srcX, srcY0, srcX + width, srcY1, strb->surface->u.tex.first_layer, dest_surface, destX, destY, destX + width, destY + height, 0.0, PIPE_TEX_MIPFILTER_NEAREST, format_writemask); pipe_surface_reference(&dest_surface, NULL); /* Restore conditional rendering state. */ if (st->render_condition) { pipe->render_condition(pipe, st->render_condition, st->condition_mode); } return; fallback: /* software fallback */ fallback_copy_texsubimage(ctx, strb, stImage, texBaseFormat, destX, destY, destZ, srcX, srcY, width, height); }
/** * Software fallback to do glDrawPixels(GL_STENCIL_INDEX) when we * can't use a fragment shader to write stencil values. */ static void draw_stencil_pixels(struct gl_context *ctx, GLint x, GLint y, GLsizei width, GLsizei height, GLenum format, GLenum type, const struct gl_pixelstore_attrib *unpack, const GLvoid *pixels) { struct st_context *st = st_context(ctx); struct pipe_context *pipe = st->pipe; struct st_renderbuffer *strb; enum pipe_transfer_usage usage; struct pipe_transfer *pt; const GLboolean zoom = ctx->Pixel.ZoomX != 1.0 || ctx->Pixel.ZoomY != 1.0; GLint skipPixels; ubyte *stmap; struct gl_pixelstore_attrib clippedUnpack = *unpack; if (!zoom) { if (!_mesa_clip_drawpixels(ctx, &x, &y, &width, &height, &clippedUnpack)) { /* totally clipped */ return; } } strb = st_renderbuffer(ctx->DrawBuffer-> Attachment[BUFFER_STENCIL].Renderbuffer); if (st_fb_orientation(ctx->DrawBuffer) == Y_0_TOP) { y = ctx->DrawBuffer->Height - y - height; } if(format != GL_DEPTH_STENCIL && util_format_get_component_bits(strb->format, UTIL_FORMAT_COLORSPACE_ZS, 0) != 0) usage = PIPE_TRANSFER_READ_WRITE; else usage = PIPE_TRANSFER_WRITE; pt = pipe_get_transfer(pipe, strb->texture, strb->rtt_level, strb->rtt_face + strb->rtt_slice, usage, x, y, width, height); stmap = pipe_transfer_map(pipe, pt); pixels = _mesa_map_pbo_source(ctx, &clippedUnpack, pixels); assert(pixels); /* if width > MAX_WIDTH, have to process image in chunks */ skipPixels = 0; while (skipPixels < width) { const GLint spanX = skipPixels; const GLint spanWidth = MIN2(width - skipPixels, MAX_WIDTH); GLint row; for (row = 0; row < height; row++) { GLubyte sValues[MAX_WIDTH]; GLuint zValues[MAX_WIDTH]; GLenum destType = GL_UNSIGNED_BYTE; const GLvoid *source = _mesa_image_address2d(&clippedUnpack, pixels, width, height, format, type, row, skipPixels); _mesa_unpack_stencil_span(ctx, spanWidth, destType, sValues, type, source, &clippedUnpack, ctx->_ImageTransferState); if (format == GL_DEPTH_STENCIL) { _mesa_unpack_depth_span(ctx, spanWidth, GL_UNSIGNED_INT, zValues, (1 << 24) - 1, type, source, &clippedUnpack); } if (zoom) { _mesa_problem(ctx, "Gallium glDrawPixels(GL_STENCIL) with " "zoom not complete"); } { GLint spanY; if (st_fb_orientation(ctx->DrawBuffer) == Y_0_TOP) { spanY = height - row - 1; } else { spanY = row; } /* now pack the stencil (and Z) values in the dest format */ switch (pt->resource->format) { case PIPE_FORMAT_S8_USCALED: { ubyte *dest = stmap + spanY * pt->stride + spanX; assert(usage == PIPE_TRANSFER_WRITE); memcpy(dest, sValues, spanWidth); } break; case PIPE_FORMAT_Z24_UNORM_S8_USCALED: if (format == GL_DEPTH_STENCIL) { uint *dest = (uint *) (stmap + spanY * pt->stride + spanX*4); GLint k; assert(usage == PIPE_TRANSFER_WRITE); for (k = 0; k < spanWidth; k++) { dest[k] = zValues[k] | (sValues[k] << 24); } } else { uint *dest = (uint *) (stmap + spanY * pt->stride + spanX*4); GLint k; assert(usage == PIPE_TRANSFER_READ_WRITE); for (k = 0; k < spanWidth; k++) { dest[k] = (dest[k] & 0xffffff) | (sValues[k] << 24); } } break; case PIPE_FORMAT_S8_USCALED_Z24_UNORM: if (format == GL_DEPTH_STENCIL) { uint *dest = (uint *) (stmap + spanY * pt->stride + spanX*4); GLint k; assert(usage == PIPE_TRANSFER_WRITE); for (k = 0; k < spanWidth; k++) { dest[k] = (zValues[k] << 8) | (sValues[k] & 0xff); } } else { uint *dest = (uint *) (stmap + spanY * pt->stride + spanX*4); GLint k; assert(usage == PIPE_TRANSFER_READ_WRITE); for (k = 0; k < spanWidth; k++) { dest[k] = (dest[k] & 0xffffff00) | (sValues[k] & 0xff); } } break; default: assert(0); } } } skipPixels += spanWidth; } _mesa_unmap_pbo_source(ctx, &clippedUnpack); /* unmap the stencil buffer */ pipe_transfer_unmap(pipe, pt); pipe->transfer_destroy(pipe, pt); }
static void draw_textured_quad(struct gl_context *ctx, GLint x, GLint y, GLfloat z, GLsizei width, GLsizei height, GLfloat zoomX, GLfloat zoomY, struct pipe_sampler_view **sv, int num_sampler_view, void *driver_vp, void *driver_fp, const GLfloat *color, GLboolean invertTex, GLboolean write_depth, GLboolean write_stencil) { struct st_context *st = st_context(ctx); struct pipe_context *pipe = st->pipe; struct cso_context *cso = st->cso_context; GLfloat x0, y0, x1, y1; GLsizei maxSize; boolean normalized = sv[0]->texture->target != PIPE_TEXTURE_RECT; /* limit checks */ /* XXX if DrawPixels image is larger than 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 <= maxSize); assert(height <= maxSize); cso_save_rasterizer(cso); cso_save_viewport(cso); cso_save_samplers(cso); cso_save_fragment_sampler_views(cso); cso_save_fragment_shader(cso); cso_save_vertex_shader(cso); cso_save_vertex_elements(cso); cso_save_vertex_buffers(cso); if (write_stencil) { cso_save_depth_stencil_alpha(cso); cso_save_blend(cso); } /* rasterizer state: just scissor */ { struct pipe_rasterizer_state rasterizer; memset(&rasterizer, 0, sizeof(rasterizer)); rasterizer.clamp_fragment_color = ctx->Color._ClampFragmentColor; rasterizer.gl_rasterization_rules = 1; rasterizer.scissor = ctx->Scissor.Enabled; cso_set_rasterizer(cso, &rasterizer); } if (write_stencil) { /* Stencil writing bypasses the normal fragment pipeline to * disable color writing and set stencil test to always pass. */ struct pipe_depth_stencil_alpha_state dsa; struct pipe_blend_state blend; /* depth/stencil */ memset(&dsa, 0, sizeof(dsa)); dsa.stencil[0].enabled = 1; dsa.stencil[0].func = PIPE_FUNC_ALWAYS; dsa.stencil[0].writemask = ctx->Stencil.WriteMask[0] & 0xff; dsa.stencil[0].zpass_op = PIPE_STENCIL_OP_REPLACE; if (write_depth) { /* writing depth+stencil: depth test always passes */ dsa.depth.enabled = 1; dsa.depth.writemask = ctx->Depth.Mask; dsa.depth.func = PIPE_FUNC_ALWAYS; } cso_set_depth_stencil_alpha(cso, &dsa); /* blend (colormask) */ memset(&blend, 0, sizeof(blend)); cso_set_blend(cso, &blend); } /* fragment shader state: TEX lookup program */ cso_set_fragment_shader_handle(cso, driver_fp); /* vertex shader state: position + texcoord pass-through */ cso_set_vertex_shader_handle(cso, driver_vp); /* texture sampling state: */ { struct pipe_sampler_state sampler; memset(&sampler, 0, sizeof(sampler)); sampler.wrap_s = PIPE_TEX_WRAP_CLAMP; sampler.wrap_t = PIPE_TEX_WRAP_CLAMP; sampler.wrap_r = PIPE_TEX_WRAP_CLAMP; sampler.min_img_filter = PIPE_TEX_FILTER_NEAREST; sampler.min_mip_filter = PIPE_TEX_MIPFILTER_NONE; sampler.mag_img_filter = PIPE_TEX_FILTER_NEAREST; sampler.normalized_coords = normalized; cso_single_sampler(cso, 0, &sampler); if (num_sampler_view > 1) { cso_single_sampler(cso, 1, &sampler); } cso_single_sampler_done(cso); } /* viewport state: viewport matching window dims */ { const float w = (float) ctx->DrawBuffer->Width; const float h = (float) ctx->DrawBuffer->Height; struct pipe_viewport_state vp; vp.scale[0] = 0.5f * w; vp.scale[1] = -0.5f * h; vp.scale[2] = 0.5f; vp.scale[3] = 1.0f; vp.translate[0] = 0.5f * w; vp.translate[1] = 0.5f * h; 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); /* texture state: */ cso_set_fragment_sampler_views(cso, num_sampler_view, sv); /* Compute Gallium window coords (y=0=top) with pixel zoom. * Recall that these coords are transformed by the current * vertex shader and viewport transformation. */ if (st_fb_orientation(ctx->DrawBuffer) == Y_0_BOTTOM) { y = ctx->DrawBuffer->Height - (int) (y + height * ctx->Pixel.ZoomY); invertTex = !invertTex; } x0 = (GLfloat) x; x1 = x + width * ctx->Pixel.ZoomX; y0 = (GLfloat) y; y1 = y + height * ctx->Pixel.ZoomY; /* convert Z from [0,1] to [-1,-1] to match viewport Z scale/bias */ z = z * 2.0 - 1.0; draw_quad(ctx, x0, y0, z, x1, y1, color, invertTex, normalized ? ((GLfloat) width / sv[0]->texture->width0) : (GLfloat)width, normalized ? ((GLfloat) height / sv[0]->texture->height0) : (GLfloat)height); /* restore state */ cso_restore_rasterizer(cso); cso_restore_viewport(cso); cso_restore_samplers(cso); cso_restore_fragment_sampler_views(cso); cso_restore_fragment_shader(cso); cso_restore_vertex_shader(cso); cso_restore_vertex_elements(cso); cso_restore_vertex_buffers(cso); if (write_stencil) { cso_restore_depth_stencil_alpha(cso); cso_restore_blend(cso); } }
static void st_CopyPixels(struct gl_context *ctx, GLint srcx, GLint srcy, GLsizei width, GLsizei height, GLint dstx, GLint dsty, GLenum type) { struct st_context *st = st_context(ctx); struct pipe_context *pipe = st->pipe; struct pipe_screen *screen = pipe->screen; struct st_renderbuffer *rbRead; void *driver_vp, *driver_fp; struct pipe_resource *pt; struct pipe_sampler_view *sv[2]; int num_sampler_view = 1; GLfloat *color; enum pipe_format srcFormat, texFormat; GLboolean invertTex = GL_FALSE; GLint readX, readY, readW, readH; GLuint sample_count; struct gl_pixelstore_attrib pack = ctx->DefaultPacking; struct st_fp_variant *fpv; st_validate_state(st); if (type == GL_STENCIL) { /* can't use texturing to do stencil */ copy_stencil_pixels(ctx, srcx, srcy, width, height, dstx, dsty); return; } if (blit_copy_pixels(ctx, srcx, srcy, width, height, dstx, dsty, type)) return; /* * The subsequent code implements glCopyPixels by copying the source * pixels into a temporary texture that's then applied to a textured quad. * When we draw the textured quad, all the usual per-fragment operations * are handled. */ /* * Get vertex/fragment shaders */ if (type == GL_COLOR) { rbRead = st_get_color_read_renderbuffer(ctx); color = NULL; fpv = get_color_fp_variant(st); driver_fp = fpv->driver_shader; driver_vp = make_passthrough_vertex_shader(st, GL_FALSE); if (st->pixel_xfer.pixelmap_enabled) { sv[1] = st->pixel_xfer.pixelmap_sampler_view; num_sampler_view++; } } else { assert(type == GL_DEPTH); rbRead = st_renderbuffer(ctx->ReadBuffer->_DepthBuffer); color = ctx->Current.Attrib[VERT_ATTRIB_COLOR0]; fpv = get_depth_stencil_fp_variant(st, GL_TRUE, GL_FALSE); driver_fp = fpv->driver_shader; driver_vp = make_passthrough_vertex_shader(st, GL_TRUE); } /* update fragment program constants */ st_upload_constants(st, fpv->parameters, PIPE_SHADER_FRAGMENT); if (rbRead->Base.Wrapped) rbRead = st_renderbuffer(rbRead->Base.Wrapped); sample_count = rbRead->texture->nr_samples; /* I believe this would be legal, presumably would need to do a resolve for color, and for depth/stencil spec says to just use one of the depth/stencil samples per pixel? Need some transfer clarifications. */ assert(sample_count < 2); srcFormat = rbRead->texture->format; if (screen->is_format_supported(screen, srcFormat, st->internal_target, sample_count, PIPE_BIND_SAMPLER_VIEW)) { texFormat = srcFormat; } else { /* srcFormat can't be used as a texture format */ if (type == GL_DEPTH) { texFormat = st_choose_format(screen, GL_DEPTH_COMPONENT, GL_NONE, GL_NONE, st->internal_target, sample_count, PIPE_BIND_DEPTH_STENCIL); assert(texFormat != PIPE_FORMAT_NONE); } else { /* default color format */ texFormat = st_choose_format(screen, GL_RGBA, GL_NONE, GL_NONE, st->internal_target, sample_count, PIPE_BIND_SAMPLER_VIEW); assert(texFormat != PIPE_FORMAT_NONE); } } /* Invert src region if needed */ if (st_fb_orientation(ctx->ReadBuffer) == Y_0_TOP) { srcy = ctx->ReadBuffer->Height - srcy - height; invertTex = !invertTex; } /* Clip the read region against the src buffer bounds. * We'll still allocate a temporary buffer/texture for the original * src region size but we'll only read the region which is on-screen. * This may mean that we draw garbage pixels into the dest region, but * that's expected. */ readX = srcx; readY = srcy; readW = width; readH = height; _mesa_clip_readpixels(ctx, &readX, &readY, &readW, &readH, &pack); readW = MAX2(0, readW); readH = MAX2(0, readH); /* alloc temporary texture */ pt = alloc_texture(st, width, height, texFormat); if (!pt) return; sv[0] = st_create_texture_sampler_view(st->pipe, pt); if (!sv[0]) { pipe_resource_reference(&pt, NULL); return; } /* Make temporary texture which is a copy of the src region. */ if (srcFormat == texFormat) { struct pipe_box src_box; u_box_2d(readX, readY, readW, readH, &src_box); /* copy source framebuffer surface into mipmap/texture */ pipe->resource_copy_region(pipe, pt, /* dest tex */ 0, /* dest lvl */ pack.SkipPixels, pack.SkipRows, 0, /* dest pos */ rbRead->texture, /* src tex */ rbRead->rtt_level, /* src lvl */ &src_box); } else { /* CPU-based fallback/conversion */ struct pipe_transfer *ptRead = pipe_get_transfer(st->pipe, rbRead->texture, rbRead->rtt_level, rbRead->rtt_face + rbRead->rtt_slice, PIPE_TRANSFER_READ, readX, readY, readW, readH); struct pipe_transfer *ptTex; enum pipe_transfer_usage transfer_usage; if (ST_DEBUG & DEBUG_FALLBACK) debug_printf("%s: fallback processing\n", __FUNCTION__); if (type == GL_DEPTH && util_format_is_depth_and_stencil(pt->format)) transfer_usage = PIPE_TRANSFER_READ_WRITE; else transfer_usage = PIPE_TRANSFER_WRITE; ptTex = pipe_get_transfer(st->pipe, pt, 0, 0, transfer_usage, 0, 0, width, height); /* copy image from ptRead surface to ptTex surface */ if (type == GL_COLOR) { /* alternate path using get/put_tile() */ GLfloat *buf = (GLfloat *) malloc(width * height * 4 * sizeof(GLfloat)); enum pipe_format readFormat, drawFormat; readFormat = util_format_linear(rbRead->texture->format); drawFormat = util_format_linear(pt->format); pipe_get_tile_rgba_format(pipe, ptRead, 0, 0, readW, readH, readFormat, buf); pipe_put_tile_rgba_format(pipe, ptTex, pack.SkipPixels, pack.SkipRows, readW, readH, drawFormat, buf); free(buf); } else { /* GL_DEPTH */ GLuint *buf = (GLuint *) malloc(width * height * sizeof(GLuint)); pipe_get_tile_z(pipe, ptRead, 0, 0, readW, readH, buf); pipe_put_tile_z(pipe, ptTex, pack.SkipPixels, pack.SkipRows, readW, readH, buf); free(buf); } pipe->transfer_destroy(pipe, ptRead); pipe->transfer_destroy(pipe, ptTex); } /* OK, the texture 'pt' contains the src image/pixels. Now draw a * textured quad with that texture. */ draw_textured_quad(ctx, dstx, dsty, ctx->Current.RasterPos[2], width, height, ctx->Pixel.ZoomX, ctx->Pixel.ZoomY, sv, num_sampler_view, driver_vp, driver_fp, color, invertTex, GL_FALSE, GL_FALSE); pipe_resource_reference(&pt, NULL); pipe_sampler_view_reference(&sv[0], NULL); }
/** * Try to do a glCopyPixels for simple cases with a blit by calling * pipe->resource_copy_region(). * * We can do this when we're copying color pixels (depth/stencil * eventually) with no pixel zoom, no pixel transfer ops, no * per-fragment ops, the src/dest regions don't overlap and the * src/dest pixel formats are the same. */ static GLboolean blit_copy_pixels(struct gl_context *ctx, GLint srcx, GLint srcy, GLsizei width, GLsizei height, GLint dstx, GLint dsty, GLenum type) { struct st_context *st = st_context(ctx); struct pipe_context *pipe = st->pipe; struct gl_pixelstore_attrib pack, unpack; GLint readX, readY, readW, readH; if (type == GL_COLOR && ctx->Pixel.ZoomX == 1.0 && ctx->Pixel.ZoomY == 1.0 && ctx->_ImageTransferState == 0x0 && !ctx->Color.BlendEnabled && !ctx->Color.AlphaEnabled && !ctx->Depth.Test && !ctx->Fog.Enabled && !ctx->Stencil.Enabled && !ctx->FragmentProgram.Enabled && !ctx->VertexProgram.Enabled && !ctx->Shader.CurrentFragmentProgram && st_fb_orientation(ctx->ReadBuffer) == st_fb_orientation(ctx->DrawBuffer) && ctx->DrawBuffer->_NumColorDrawBuffers == 1 && !ctx->Query.CondRenderQuery) { struct st_renderbuffer *rbRead, *rbDraw; GLint drawX, drawY; /* * Clip the read region against the src buffer bounds. * We'll still allocate a temporary buffer/texture for the original * src region size but we'll only read the region which is on-screen. * This may mean that we draw garbage pixels into the dest region, but * that's expected. */ readX = srcx; readY = srcy; readW = width; readH = height; pack = ctx->DefaultPacking; if (!_mesa_clip_readpixels(ctx, &readX, &readY, &readW, &readH, &pack)) return GL_TRUE; /* all done */ /* clip against dest buffer bounds and scissor box */ drawX = dstx + pack.SkipPixels; drawY = dsty + pack.SkipRows; unpack = pack; if (!_mesa_clip_drawpixels(ctx, &drawX, &drawY, &readW, &readH, &unpack)) return GL_TRUE; /* all done */ readX = readX - pack.SkipPixels + unpack.SkipPixels; readY = readY - pack.SkipRows + unpack.SkipRows; rbRead = st_get_color_read_renderbuffer(ctx); rbDraw = st_renderbuffer(ctx->DrawBuffer->_ColorDrawBuffers[0]); if ((rbRead != rbDraw || !regions_overlap(readX, readY, drawX, drawY, readW, readH)) && rbRead->Base.Format == rbDraw->Base.Format) { struct pipe_box srcBox; /* flip src/dst position if needed */ if (st_fb_orientation(ctx->ReadBuffer) == Y_0_TOP) { /* both buffers will have the same orientation */ readY = ctx->ReadBuffer->Height - readY - readH; drawY = ctx->DrawBuffer->Height - drawY - readH; } u_box_2d(readX, readY, readW, readH, &srcBox); pipe->resource_copy_region(pipe, rbDraw->texture, rbDraw->rtt_level, drawX, drawY, 0, rbRead->texture, rbRead->rtt_level, &srcBox); return GL_TRUE; } } return GL_FALSE; }
/** * Software fallback for glCopyPixels(GL_STENCIL). */ static void copy_stencil_pixels(struct gl_context *ctx, GLint srcx, GLint srcy, GLsizei width, GLsizei height, GLint dstx, GLint dsty) { struct st_renderbuffer *rbDraw; struct pipe_context *pipe = st_context(ctx)->pipe; enum pipe_transfer_usage usage; struct pipe_transfer *ptDraw; ubyte *drawMap; ubyte *buffer; int i; buffer = malloc(width * height * sizeof(ubyte)); if (!buffer) { _mesa_error(ctx, GL_OUT_OF_MEMORY, "glCopyPixels(stencil)"); return; } /* Get the dest renderbuffer. If there's a wrapper, use the * underlying renderbuffer. */ rbDraw = st_renderbuffer(ctx->DrawBuffer->_StencilBuffer); if (rbDraw->Base.Wrapped) rbDraw = st_renderbuffer(rbDraw->Base.Wrapped); /* this will do stencil pixel transfer ops */ st_read_stencil_pixels(ctx, srcx, srcy, width, height, GL_STENCIL_INDEX, GL_UNSIGNED_BYTE, &ctx->DefaultPacking, buffer); if (0) { /* debug code: dump stencil values */ GLint row, col; for (row = 0; row < height; row++) { printf("%3d: ", row); for (col = 0; col < width; col++) { printf("%02x ", buffer[col + row * width]); } printf("\n"); } } if (util_format_get_component_bits(rbDraw->format, UTIL_FORMAT_COLORSPACE_ZS, 0) != 0) usage = PIPE_TRANSFER_READ_WRITE; else usage = PIPE_TRANSFER_WRITE; if (st_fb_orientation(ctx->DrawBuffer) == Y_0_TOP) { dsty = rbDraw->Base.Height - dsty - height; } ptDraw = pipe_get_transfer(pipe, rbDraw->texture, rbDraw->rtt_level, rbDraw->rtt_face + rbDraw->rtt_slice, usage, dstx, dsty, width, height); assert(util_format_get_blockwidth(ptDraw->resource->format) == 1); assert(util_format_get_blockheight(ptDraw->resource->format) == 1); /* map the stencil buffer */ drawMap = pipe_transfer_map(pipe, ptDraw); /* draw */ /* XXX PixelZoom not handled yet */ for (i = 0; i < height; i++) { ubyte *dst; const ubyte *src; int y; y = i; if (st_fb_orientation(ctx->DrawBuffer) == Y_0_TOP) { y = height - y - 1; } dst = drawMap + y * ptDraw->stride; src = buffer + i * width; switch (ptDraw->resource->format) { case PIPE_FORMAT_Z24_UNORM_S8_USCALED: { uint *dst4 = (uint *) dst; int j; assert(usage == PIPE_TRANSFER_READ_WRITE); for (j = 0; j < width; j++) { *dst4 = (*dst4 & 0xffffff) | (src[j] << 24); dst4++; } } break; case PIPE_FORMAT_S8_USCALED_Z24_UNORM: { uint *dst4 = (uint *) dst; int j; assert(usage == PIPE_TRANSFER_READ_WRITE); for (j = 0; j < width; j++) { *dst4 = (*dst4 & 0xffffff00) | (src[j] & 0xff); dst4++; } } break; case PIPE_FORMAT_S8_USCALED: assert(usage == PIPE_TRANSFER_WRITE); memcpy(dst, src, width); break; default: assert(0); } } free(buffer); /* unmap the stencil buffer */ pipe_transfer_unmap(pipe, ptDraw); pipe->transfer_destroy(pipe, ptDraw); }
/** * Do glClear by drawing a quadrilateral. * The vertices of the quad will be computed from the * ctx->DrawBuffer->_X/Ymin/max fields. */ static void clear_with_quad(struct gl_context *ctx, GLboolean color, GLboolean depth, GLboolean stencil) { struct st_context *st = st_context(ctx); const struct gl_framebuffer *fb = ctx->DrawBuffer; const GLfloat fb_width = (GLfloat) fb->Width; const GLfloat fb_height = (GLfloat) fb->Height; const GLfloat x0 = (GLfloat) ctx->DrawBuffer->_Xmin / fb_width * 2.0f - 1.0f; const GLfloat x1 = (GLfloat) ctx->DrawBuffer->_Xmax / fb_width * 2.0f - 1.0f; const GLfloat y0 = (GLfloat) ctx->DrawBuffer->_Ymin / fb_height * 2.0f - 1.0f; const GLfloat y1 = (GLfloat) ctx->DrawBuffer->_Ymax / fb_height * 2.0f - 1.0f; union pipe_color_union clearColor; /* printf("%s %s%s%s %f,%f %f,%f\n", __FUNCTION__, color ? "color, " : "", depth ? "depth, " : "", stencil ? "stencil" : "", x0, y0, x1, y1); */ cso_save_blend(st->cso_context); cso_save_stencil_ref(st->cso_context); cso_save_depth_stencil_alpha(st->cso_context); cso_save_rasterizer(st->cso_context); cso_save_viewport(st->cso_context); cso_save_fragment_shader(st->cso_context); cso_save_stream_outputs(st->cso_context); cso_save_vertex_shader(st->cso_context); cso_save_geometry_shader(st->cso_context); cso_save_vertex_elements(st->cso_context); cso_save_vertex_buffers(st->cso_context); /* blend state: RGBA masking */ { struct pipe_blend_state blend; memset(&blend, 0, sizeof(blend)); blend.rt[0].rgb_src_factor = PIPE_BLENDFACTOR_ONE; blend.rt[0].alpha_src_factor = PIPE_BLENDFACTOR_ONE; blend.rt[0].rgb_dst_factor = PIPE_BLENDFACTOR_ZERO; blend.rt[0].alpha_dst_factor = PIPE_BLENDFACTOR_ZERO; if (color) { if (ctx->Color.ColorMask[0][0]) blend.rt[0].colormask |= PIPE_MASK_R; if (ctx->Color.ColorMask[0][1]) blend.rt[0].colormask |= PIPE_MASK_G; if (ctx->Color.ColorMask[0][2]) blend.rt[0].colormask |= PIPE_MASK_B; if (ctx->Color.ColorMask[0][3]) blend.rt[0].colormask |= PIPE_MASK_A; if (st->ctx->Color.DitherFlag) blend.dither = 1; } cso_set_blend(st->cso_context, &blend); } /* depth_stencil state: always pass/set to ref value */ { struct pipe_depth_stencil_alpha_state depth_stencil; memset(&depth_stencil, 0, sizeof(depth_stencil)); if (depth) { depth_stencil.depth.enabled = 1; depth_stencil.depth.writemask = 1; depth_stencil.depth.func = PIPE_FUNC_ALWAYS; } if (stencil) { struct pipe_stencil_ref stencil_ref; memset(&stencil_ref, 0, sizeof(stencil_ref)); depth_stencil.stencil[0].enabled = 1; depth_stencil.stencil[0].func = PIPE_FUNC_ALWAYS; depth_stencil.stencil[0].fail_op = PIPE_STENCIL_OP_REPLACE; depth_stencil.stencil[0].zpass_op = PIPE_STENCIL_OP_REPLACE; depth_stencil.stencil[0].zfail_op = PIPE_STENCIL_OP_REPLACE; depth_stencil.stencil[0].valuemask = 0xff; depth_stencil.stencil[0].writemask = ctx->Stencil.WriteMask[0] & 0xff; stencil_ref.ref_value[0] = ctx->Stencil.Clear; cso_set_stencil_ref(st->cso_context, &stencil_ref); } cso_set_depth_stencil_alpha(st->cso_context, &depth_stencil); } cso_set_vertex_elements(st->cso_context, 2, st->velems_util_draw); cso_set_stream_outputs(st->cso_context, 0, NULL, 0); cso_set_rasterizer(st->cso_context, &st->clear.raster); /* viewport state: viewport matching window dims */ { const GLboolean invert = (st_fb_orientation(fb) == Y_0_TOP); struct pipe_viewport_state vp; vp.scale[0] = 0.5f * fb_width; vp.scale[1] = fb_height * (invert ? -0.5f : 0.5f); 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(st->cso_context, &vp); } set_fragment_shader(st); set_vertex_shader(st); cso_set_geometry_shader_handle(st->cso_context, NULL); if (ctx->DrawBuffer->_ColorDrawBuffers[0]) { st_translate_color(ctx->Color.ClearColor.f, ctx->DrawBuffer->_ColorDrawBuffers[0]->_BaseFormat, clearColor.f); } /* draw quad matching scissor rect */ draw_quad(st, x0, y0, x1, y1, (GLfloat) ctx->Depth.Clear, &clearColor); /* Restore pipe state */ cso_restore_blend(st->cso_context); cso_restore_stencil_ref(st->cso_context); cso_restore_depth_stencil_alpha(st->cso_context); cso_restore_rasterizer(st->cso_context); cso_restore_viewport(st->cso_context); cso_restore_fragment_shader(st->cso_context); cso_restore_vertex_shader(st->cso_context); cso_restore_geometry_shader(st->cso_context); cso_restore_vertex_elements(st->cso_context); cso_restore_vertex_buffers(st->cso_context); cso_restore_stream_outputs(st->cso_context); }
/** * Do glClear by drawing a quadrilateral. * The vertices of the quad will be computed from the * ctx->DrawBuffer->_X/Ymin/max fields. */ static void clear_with_quad(GLcontext *ctx, GLboolean color, GLboolean depth, GLboolean stencil) { struct st_context *st = ctx->st; const GLfloat x0 = (GLfloat) ctx->DrawBuffer->_Xmin; const GLfloat x1 = (GLfloat) ctx->DrawBuffer->_Xmax; GLfloat y0, y1; if (st_fb_orientation(ctx->DrawBuffer) == Y_0_TOP) { y0 = (GLfloat) (ctx->DrawBuffer->Height - ctx->DrawBuffer->_Ymax); y1 = (GLfloat) (ctx->DrawBuffer->Height - ctx->DrawBuffer->_Ymin); } else { y0 = (GLfloat) ctx->DrawBuffer->_Ymin; y1 = (GLfloat) ctx->DrawBuffer->_Ymax; } /* printf("%s %s%s%s %f,%f %f,%f\n", __FUNCTION__, color ? "color, " : "", depth ? "depth, " : "", stencil ? "stencil" : "", x0, y0, x1, y1); */ cso_save_blend(st->cso_context); cso_save_depth_stencil_alpha(st->cso_context); cso_save_rasterizer(st->cso_context); cso_save_fragment_shader(st->cso_context); cso_save_vertex_shader(st->cso_context); /* blend state: RGBA masking */ { struct pipe_blend_state blend; memset(&blend, 0, sizeof(blend)); blend.rgb_src_factor = PIPE_BLENDFACTOR_ONE; blend.alpha_src_factor = PIPE_BLENDFACTOR_ONE; blend.rgb_dst_factor = PIPE_BLENDFACTOR_ZERO; blend.alpha_dst_factor = PIPE_BLENDFACTOR_ZERO; if (color) { if (ctx->Color.ColorMask[0]) blend.colormask |= PIPE_MASK_R; if (ctx->Color.ColorMask[1]) blend.colormask |= PIPE_MASK_G; if (ctx->Color.ColorMask[2]) blend.colormask |= PIPE_MASK_B; if (ctx->Color.ColorMask[3]) blend.colormask |= PIPE_MASK_A; if (st->ctx->Color.DitherFlag) blend.dither = 1; } cso_set_blend(st->cso_context, &blend); } /* depth_stencil state: always pass/set to ref value */ { struct pipe_depth_stencil_alpha_state depth_stencil; memset(&depth_stencil, 0, sizeof(depth_stencil)); if (depth) { depth_stencil.depth.enabled = 1; depth_stencil.depth.writemask = 1; depth_stencil.depth.func = PIPE_FUNC_ALWAYS; } if (stencil) { depth_stencil.stencil[0].enabled = 1; depth_stencil.stencil[0].func = PIPE_FUNC_ALWAYS; depth_stencil.stencil[0].fail_op = PIPE_STENCIL_OP_REPLACE; depth_stencil.stencil[0].zpass_op = PIPE_STENCIL_OP_REPLACE; depth_stencil.stencil[0].zfail_op = PIPE_STENCIL_OP_REPLACE; depth_stencil.stencil[0].ref_value = ctx->Stencil.Clear; depth_stencil.stencil[0].valuemask = 0xff; depth_stencil.stencil[0].writemask = ctx->Stencil.WriteMask[0] & 0xff; } cso_set_depth_stencil_alpha(st->cso_context, &depth_stencil); } cso_set_rasterizer(st->cso_context, &st->clear.raster); cso_set_fragment_shader_handle(st->cso_context, st->clear.fs); cso_set_vertex_shader_handle(st->cso_context, st->clear.vs); /* draw quad matching scissor rect (XXX verify coord round-off) */ draw_quad(ctx, x0, y0, x1, y1, (GLfloat) ctx->Depth.Clear, ctx->Color.ClearColor); /* Restore pipe state */ cso_restore_blend(st->cso_context); cso_restore_depth_stencil_alpha(st->cso_context); cso_restore_rasterizer(st->cso_context); cso_restore_fragment_shader(st->cso_context); cso_restore_vertex_shader(st->cso_context); }
/** * Update framebuffer state (color, depth, stencil, etc. buffers) */ static void update_framebuffer_state( struct st_context *st ) { struct pipe_framebuffer_state *framebuffer = &st->state.framebuffer; struct gl_framebuffer *fb = st->ctx->DrawBuffer; struct st_renderbuffer *strb; GLuint i; st_flush_bitmap_cache(st); st->state.fb_orientation = st_fb_orientation(fb); framebuffer->width = fb->Width; framebuffer->height = fb->Height; /*printf("------ fb size %d x %d\n", fb->Width, fb->Height);*/ /* 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++) { pipe_surface_reference(&framebuffer->cbufs[i], NULL); strb = st_renderbuffer(fb->_ColorDrawBuffers[i]); if (strb) { if (strb->is_rtt || (strb->texture && util_format_is_srgb(strb->texture->format))) { /* rendering to a GL texture, may have to update surface */ st_update_renderbuffer_surface(st, strb); } if (strb->surface) { pipe_surface_reference(&framebuffer->cbufs[i], strb->surface); } strb->defined = GL_TRUE; /* we'll be drawing something */ } } for (i = framebuffer->nr_cbufs; i < PIPE_MAX_COLOR_BUFS; i++) { pipe_surface_reference(&framebuffer->cbufs[i], NULL); } /* * Depth/Stencil renderbuffer/surface. */ strb = st_renderbuffer(fb->Attachment[BUFFER_DEPTH].Renderbuffer); if (strb) { if (strb->is_rtt) { /* rendering to a GL texture, may have to update surface */ st_update_renderbuffer_surface(st, strb); } pipe_surface_reference(&framebuffer->zsbuf, strb->surface); } else { strb = st_renderbuffer(fb->Attachment[BUFFER_STENCIL].Renderbuffer); if (strb) { assert(strb->surface); pipe_surface_reference(&framebuffer->zsbuf, strb->surface); } else pipe_surface_reference(&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 cso_set_framebuffer(st->cso_context, framebuffer); }
static void update_raster_state( struct st_context *st ) { struct gl_context *ctx = st->ctx; struct pipe_rasterizer_state *raster = &st->state.rasterizer; const struct gl_vertex_program *vertProg = ctx->VertexProgram._Current; const struct gl_fragment_program *fragProg = ctx->FragmentProgram._Current; uint i; memset(raster, 0, sizeof(*raster)); /* _NEW_POLYGON, _NEW_BUFFERS */ { raster->front_ccw = (ctx->Polygon.FrontFace == GL_CCW); /* _NEW_TRANSFORM */ if (ctx->Transform.ClipOrigin == GL_UPPER_LEFT) { raster->front_ccw ^= 1; } /* * Gallium's surfaces are Y=0=TOP orientation. OpenGL is the * opposite. Window system surfaces are Y=0=TOP. Mesa's FBOs * must match OpenGL conventions so FBOs use Y=0=BOTTOM. In that * case, we must invert Y and flip the notion of front vs. back. */ if (st_fb_orientation(ctx->DrawBuffer) == Y_0_BOTTOM) { /* Drawing to an FBO. The viewport will be inverted. */ raster->front_ccw ^= 1; } } /* _NEW_LIGHT */ raster->flatshade = ctx->Light.ShadeModel == GL_FLAT; raster->flatshade_first = ctx->Light.ProvokingVertex == GL_FIRST_VERTEX_CONVENTION_EXT; /* _NEW_LIGHT | _NEW_PROGRAM */ raster->light_twoside = ctx->VertexProgram._TwoSideEnabled; /*_NEW_LIGHT | _NEW_BUFFERS */ raster->clamp_vertex_color = !st->clamp_vert_color_in_shader && ctx->Light._ClampVertexColor; /* _NEW_POLYGON */ if (ctx->Polygon.CullFlag) { switch (ctx->Polygon.CullFaceMode) { case GL_FRONT: raster->cull_face = PIPE_FACE_FRONT; break; case GL_BACK: raster->cull_face = PIPE_FACE_BACK; break; case GL_FRONT_AND_BACK: raster->cull_face = PIPE_FACE_FRONT_AND_BACK; break; } } else { raster->cull_face = PIPE_FACE_NONE; } /* _NEW_POLYGON */ { if (ST_DEBUG & DEBUG_WIREFRAME) { raster->fill_front = PIPE_POLYGON_MODE_LINE; raster->fill_back = PIPE_POLYGON_MODE_LINE; } else { raster->fill_front = translate_fill( ctx->Polygon.FrontMode ); raster->fill_back = translate_fill( ctx->Polygon.BackMode ); } /* Simplify when culling is active: */ if (raster->cull_face & PIPE_FACE_FRONT) { raster->fill_front = raster->fill_back; } if (raster->cull_face & PIPE_FACE_BACK) { raster->fill_back = raster->fill_front; } } /* _NEW_POLYGON */ if (ctx->Polygon.OffsetPoint || ctx->Polygon.OffsetLine || ctx->Polygon.OffsetFill) { raster->offset_point = ctx->Polygon.OffsetPoint; raster->offset_line = ctx->Polygon.OffsetLine; raster->offset_tri = ctx->Polygon.OffsetFill; raster->offset_units = ctx->Polygon.OffsetUnits; raster->offset_scale = ctx->Polygon.OffsetFactor; raster->offset_clamp = ctx->Polygon.OffsetClamp; } raster->poly_smooth = ctx->Polygon.SmoothFlag; raster->poly_stipple_enable = ctx->Polygon.StippleFlag; /* _NEW_POINT */ raster->point_size = ctx->Point.Size; raster->point_smooth = !ctx->Point.PointSprite && ctx->Point.SmoothFlag; /* _NEW_POINT | _NEW_PROGRAM */ if (ctx->Point.PointSprite) { /* origin */ if ((ctx->Point.SpriteOrigin == GL_UPPER_LEFT) ^ (st_fb_orientation(ctx->DrawBuffer) == Y_0_BOTTOM)) raster->sprite_coord_mode = PIPE_SPRITE_COORD_UPPER_LEFT; else raster->sprite_coord_mode = PIPE_SPRITE_COORD_LOWER_LEFT; /* Coord replacement flags. If bit 'k' is set that means * that we need to replace GENERIC[k] attrib with an automatically * computed texture coord. */ for (i = 0; i < MAX_TEXTURE_COORD_UNITS; i++) { if (ctx->Point.CoordReplace[i]) { raster->sprite_coord_enable |= 1 << i; } } if (!st->needs_texcoord_semantic && fragProg->Base.InputsRead & VARYING_BIT_PNTC) { raster->sprite_coord_enable |= 1 << st_get_generic_varying_index(st, VARYING_SLOT_PNTC); } raster->point_quad_rasterization = 1; } /* ST_NEW_VERTEX_PROGRAM */ if (vertProg) { if (vertProg->Base.Id == 0) { if (vertProg->Base.OutputsWritten & BITFIELD64_BIT(VARYING_SLOT_PSIZ)) { /* generated program which emits point size */ raster->point_size_per_vertex = TRUE; } } else if (ctx->API != API_OPENGLES2) { /* PointSizeEnabled is always set in ES2 contexts */ raster->point_size_per_vertex = ctx->VertexProgram.PointSizeEnabled; } else { /* ST_NEW_TESSEVAL_PROGRAM | ST_NEW_GEOMETRY_PROGRAM */ /* We have to check the last bound stage and see if it writes psize */ struct gl_program *last = NULL; if (ctx->GeometryProgram._Current) last = &ctx->GeometryProgram._Current->Base; else if (ctx->TessEvalProgram._Current) last = &ctx->TessEvalProgram._Current->Base; else if (ctx->VertexProgram._Current) last = &ctx->VertexProgram._Current->Base; if (last) raster->point_size_per_vertex = !!(last->OutputsWritten & BITFIELD64_BIT(VARYING_SLOT_PSIZ)); } } if (!raster->point_size_per_vertex) { /* clamp size now */ raster->point_size = CLAMP(ctx->Point.Size, ctx->Point.MinSize, ctx->Point.MaxSize); } /* _NEW_LINE */ raster->line_smooth = ctx->Line.SmoothFlag; if (ctx->Line.SmoothFlag) { raster->line_width = CLAMP(ctx->Line.Width, ctx->Const.MinLineWidthAA, ctx->Const.MaxLineWidthAA); } else { raster->line_width = CLAMP(ctx->Line.Width, ctx->Const.MinLineWidth, ctx->Const.MaxLineWidth); } raster->line_stipple_enable = ctx->Line.StippleFlag; raster->line_stipple_pattern = ctx->Line.StipplePattern; /* GL stipple factor is in [1,256], remap to [0, 255] here */ raster->line_stipple_factor = ctx->Line.StippleFactor - 1; /* _NEW_MULTISAMPLE */ raster->multisample = _mesa_is_multisample_enabled(ctx); /* _NEW_MULTISAMPLE | _NEW_BUFFERS */ raster->force_persample_interp = !st->force_persample_in_shader && _mesa_is_multisample_enabled(ctx) && ctx->Multisample.SampleShading && ctx->Multisample.MinSampleShadingValue * _mesa_geometric_samples(ctx->DrawBuffer) > 1; /* _NEW_SCISSOR */ raster->scissor = ctx->Scissor.EnableFlags; /* _NEW_FRAG_CLAMP */ raster->clamp_fragment_color = !st->clamp_frag_color_in_shader && ctx->Color._ClampFragmentColor; raster->half_pixel_center = 1; if (st_fb_orientation(ctx->DrawBuffer) == Y_0_TOP) raster->bottom_edge_rule = 1; /* _NEW_TRANSFORM */ if (ctx->Transform.ClipOrigin == GL_UPPER_LEFT) raster->bottom_edge_rule ^= 1; /* ST_NEW_RASTERIZER */ raster->rasterizer_discard = ctx->RasterDiscard; if (st->edgeflag_culls_prims) { /* All edge flags are FALSE. Cull the affected faces. */ if (raster->fill_front != PIPE_POLYGON_MODE_FILL) raster->cull_face |= PIPE_FACE_FRONT; if (raster->fill_back != PIPE_POLYGON_MODE_FILL) raster->cull_face |= PIPE_FACE_BACK; } /* _NEW_TRANSFORM */ raster->depth_clip = !ctx->Transform.DepthClamp; raster->clip_plane_enable = ctx->Transform.ClipPlanesEnabled; raster->clip_halfz = (ctx->Transform.ClipDepthMode == GL_ZERO_TO_ONE); cso_set_rasterizer(st->cso_context, raster); }
static void update_raster_state( struct st_context *st ) { struct gl_context *ctx = st->ctx; struct pipe_rasterizer_state *raster = &st->state.rasterizer; const struct gl_vertex_program *vertProg = ctx->VertexProgram._Current; const struct gl_fragment_program *fragProg = ctx->FragmentProgram._Current; uint i; memset(raster, 0, sizeof(*raster)); /* _NEW_POLYGON, _NEW_BUFFERS */ { raster->front_ccw = (ctx->Polygon.FrontFace == GL_CCW); /* * Gallium's surfaces are Y=0=TOP orientation. OpenGL is the * opposite. Window system surfaces are Y=0=TOP. Mesa's FBOs * must match OpenGL conventions so FBOs use Y=0=BOTTOM. In that * case, we must invert Y and flip the notion of front vs. back. */ if (st_fb_orientation(ctx->DrawBuffer) == Y_0_BOTTOM) { /* Drawing to an FBO. The viewport will be inverted. */ raster->front_ccw ^= 1; } } /* _NEW_LIGHT */ if (ctx->Light.ShadeModel == GL_FLAT) raster->flatshade = 1; if (ctx->Light.ProvokingVertex == GL_FIRST_VERTEX_CONVENTION_EXT) raster->flatshade_first = 1; /* _NEW_LIGHT | _NEW_PROGRAM */ raster->light_twoside = ctx->VertexProgram._TwoSideEnabled; /*_NEW_LIGHT | _NEW_BUFFERS */ raster->clamp_vertex_color = !st->clamp_vert_color_in_shader && ctx->Light._ClampVertexColor; /* _NEW_POLYGON */ if (ctx->Polygon.CullFlag) { switch (ctx->Polygon.CullFaceMode) { case GL_FRONT: raster->cull_face = PIPE_FACE_FRONT; break; case GL_BACK: raster->cull_face = PIPE_FACE_BACK; break; case GL_FRONT_AND_BACK: raster->cull_face = PIPE_FACE_FRONT_AND_BACK; break; } } else { raster->cull_face = PIPE_FACE_NONE; } /* _NEW_POLYGON */ { raster->fill_front = translate_fill( ctx->Polygon.FrontMode ); raster->fill_back = translate_fill( ctx->Polygon.BackMode ); /* Simplify when culling is active: */ if (raster->cull_face & PIPE_FACE_FRONT) { raster->fill_front = raster->fill_back; } if (raster->cull_face & PIPE_FACE_BACK) { raster->fill_back = raster->fill_front; } } /* _NEW_POLYGON */ if (ctx->Polygon.OffsetUnits != 0.0 || ctx->Polygon.OffsetFactor != 0.0) { raster->offset_point = ctx->Polygon.OffsetPoint; raster->offset_line = ctx->Polygon.OffsetLine; raster->offset_tri = ctx->Polygon.OffsetFill; } if (ctx->Polygon.OffsetPoint || ctx->Polygon.OffsetLine || ctx->Polygon.OffsetFill) { raster->offset_units = ctx->Polygon.OffsetUnits; raster->offset_scale = ctx->Polygon.OffsetFactor; } if (ctx->Polygon.SmoothFlag) raster->poly_smooth = 1; if (ctx->Polygon.StippleFlag) raster->poly_stipple_enable = 1; /* _NEW_POINT */ raster->point_size = ctx->Point.Size; if (!ctx->Point.PointSprite && ctx->Point.SmoothFlag) raster->point_smooth = 1; /* _NEW_POINT | _NEW_PROGRAM */ if (ctx->Point.PointSprite) { /* origin */ if ((ctx->Point.SpriteOrigin == GL_UPPER_LEFT) ^ (st_fb_orientation(ctx->DrawBuffer) == Y_0_BOTTOM)) raster->sprite_coord_mode = PIPE_SPRITE_COORD_UPPER_LEFT; else raster->sprite_coord_mode = PIPE_SPRITE_COORD_LOWER_LEFT; /* Coord replacement flags. If bit 'k' is set that means * that we need to replace GENERIC[k] attrib with an automatically * computed texture coord. */ for (i = 0; i < MAX_TEXTURE_COORD_UNITS; i++) { if (ctx->Point.CoordReplace[i]) { raster->sprite_coord_enable |= 1 << i; } } if (fragProg->Base.InputsRead & FRAG_BIT_PNTC) { raster->sprite_coord_enable |= 1 << (FRAG_ATTRIB_PNTC - FRAG_ATTRIB_TEX0); } raster->point_quad_rasterization = 1; } /* ST_NEW_VERTEX_PROGRAM */ if (vertProg) { if (vertProg->Base.Id == 0) { if (vertProg->Base.OutputsWritten & BITFIELD64_BIT(VERT_RESULT_PSIZ)) { /* generated program which emits point size */ raster->point_size_per_vertex = TRUE; } } else if (ctx->VertexProgram.PointSizeEnabled) { /* user-defined program and GL_VERTEX_PROGRAM_POINT_SIZE set */ raster->point_size_per_vertex = ctx->VertexProgram.PointSizeEnabled; } } if (!raster->point_size_per_vertex) { /* clamp size now */ raster->point_size = CLAMP(ctx->Point.Size, ctx->Point.MinSize, ctx->Point.MaxSize); } /* _NEW_LINE */ raster->line_smooth = ctx->Line.SmoothFlag; if (ctx->Line.SmoothFlag) { raster->line_width = CLAMP(ctx->Line.Width, ctx->Const.MinLineWidthAA, ctx->Const.MaxLineWidthAA); } else { raster->line_width = CLAMP(ctx->Line.Width, ctx->Const.MinLineWidth, ctx->Const.MaxLineWidth); } raster->line_stipple_enable = ctx->Line.StippleFlag; raster->line_stipple_pattern = ctx->Line.StipplePattern; /* GL stipple factor is in [1,256], remap to [0, 255] here */ raster->line_stipple_factor = ctx->Line.StippleFactor - 1; /* _NEW_MULTISAMPLE */ if (ctx->Multisample._Enabled || st->force_msaa) raster->multisample = 1; /* _NEW_SCISSOR */ if (ctx->Scissor.Enabled) raster->scissor = 1; /* _NEW_FRAG_CLAMP */ raster->clamp_fragment_color = !st->clamp_frag_color_in_shader && ctx->Color._ClampFragmentColor; raster->gl_rasterization_rules = 1; /* _NEW_RASTERIZER_DISCARD */ raster->rasterizer_discard = ctx->RasterDiscard; /* _NEW_TRANSFORM */ raster->depth_clip = ctx->Transform.DepthClamp == GL_FALSE; raster->clip_plane_enable = ctx->Transform.ClipPlanesEnabled; cso_set_rasterizer(st->cso_context, raster); }
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 = ctx->st->cso_context; struct pipe_resource *vbuffer; struct pipe_transfer *vbuffer_transfer; 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]; GLbitfield inputs = VERT_BIT_POS; st_validate_state(st); /* determine if we need vertex color */ if (ctx->FragmentProgram._Current->Base.InputsRead & FRAG_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]._ReallyEnabled & TEXTURE_2D_BIT) { inputs |= VERT_BIT_TEX(i); numTexCoords++; } } /* total number of attributes per vertex */ numAttribs = 1 + emitColor + numTexCoords; /* create the vertex buffer */ vbuffer = pipe_buffer_create(pipe->screen, PIPE_BIND_VERTEX_BUFFER, PIPE_USAGE_STREAM, numAttribs * 4 * 4 * sizeof(GLfloat)); /* 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 = (GLfloat *) pipe_buffer_map(pipe, vbuffer, PIPE_TRANSFER_WRITE, &vbuffer_transfer); GLuint attr; z = CLAMP(z, 0.0f, 1.0f); /* positions (in clip coords) */ { const struct gl_framebuffer *fb = st->ctx->DrawBuffer; const GLfloat fb_width = (GLfloat)fb->Width; const GLfloat fb_height = (GLfloat)fb->Height; 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; attr = 2; } else { attr = 1; } /* texcoords */ for (i = 0; i < ctx->Const.MaxTextureUnits; i++) { if (ctx->Texture.Unit[i]._ReallyEnabled & TEXTURE_2D_BIT) { struct gl_texture_object *obj = ctx->Texture.Unit[i]._Current; struct gl_texture_image *img = obj->Image[0][obj->BaseLevel]; 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, attr, s0, t0, 0.0f, 1.0f); /* lower left */ SET_ATTRIB(1, attr, s1, t0, 0.0f, 1.0f); /* lower right */ SET_ATTRIB(2, attr, s1, t1, 0.0f, 1.0f); /* upper right */ SET_ATTRIB(3, attr, s0, t1, 0.0f, 1.0f); /* upper left */ semantic_names[attr] = TGSI_SEMANTIC_GENERIC; semantic_indexes[attr] = 0; attr++; } } pipe_buffer_unmap(pipe, vbuffer_transfer); #undef SET_ATTRIB } cso_save_viewport(cso); cso_save_vertex_shader(cso); cso_save_vertex_elements(cso); cso_save_vertex_buffers(cso); { void *vs = lookup_shader(pipe, numAttribs, semantic_names, semantic_indexes); cso_set_vertex_shader_handle(cso, vs); } 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); /* viewport state: viewport matching window dims */ { const struct gl_framebuffer *fb = st->ctx->DrawBuffer; const GLboolean invert = (st_fb_orientation(fb) == Y_0_TOP); const GLfloat width = (GLfloat)fb->Width; const GLfloat height = (GLfloat)fb->Height; 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.scale[3] = 1.0f; vp.translate[0] = 0.5f * width; vp.translate[1] = 0.5f * height; vp.translate[2] = 0.0f; vp.translate[3] = 0.0f; cso_set_viewport(cso, &vp); } util_draw_vertex_buffer(pipe, cso, vbuffer, 0, /* offset */ PIPE_PRIM_TRIANGLE_FAN, 4, /* verts */ numAttribs); /* attribs/vert */ pipe_resource_reference(&vbuffer, NULL); /* restore state */ cso_restore_viewport(cso); cso_restore_vertex_shader(cso); cso_restore_vertex_elements(cso); cso_restore_vertex_buffers(cso); }
/** * Do glClear by drawing a quadrilateral. * The vertices of the quad will be computed from the * ctx->DrawBuffer->_X/Ymin/max fields. */ static void clear_with_quad(struct gl_context *ctx, unsigned clear_buffers) { struct st_context *st = st_context(ctx); const struct gl_framebuffer *fb = ctx->DrawBuffer; const GLfloat fb_width = (GLfloat) fb->Width; const GLfloat fb_height = (GLfloat) fb->Height; const GLfloat x0 = (GLfloat) ctx->DrawBuffer->_Xmin / fb_width * 2.0f - 1.0f; const GLfloat x1 = (GLfloat) ctx->DrawBuffer->_Xmax / fb_width * 2.0f - 1.0f; const GLfloat y0 = (GLfloat) ctx->DrawBuffer->_Ymin / fb_height * 2.0f - 1.0f; const GLfloat y1 = (GLfloat) ctx->DrawBuffer->_Ymax / fb_height * 2.0f - 1.0f; unsigned num_layers = util_framebuffer_get_num_layers(&st->state.framebuffer); /* printf("%s %s%s%s %f,%f %f,%f\n", __FUNCTION__, color ? "color, " : "", depth ? "depth, " : "", stencil ? "stencil" : "", x0, y0, x1, y1); */ cso_save_blend(st->cso_context); cso_save_stencil_ref(st->cso_context); cso_save_depth_stencil_alpha(st->cso_context); cso_save_rasterizer(st->cso_context); cso_save_sample_mask(st->cso_context); cso_save_viewport(st->cso_context); cso_save_fragment_shader(st->cso_context); cso_save_stream_outputs(st->cso_context); cso_save_vertex_shader(st->cso_context); cso_save_geometry_shader(st->cso_context); cso_save_vertex_elements(st->cso_context); cso_save_aux_vertex_buffer_slot(st->cso_context); /* blend state: RGBA masking */ { struct pipe_blend_state blend; memset(&blend, 0, sizeof(blend)); if (clear_buffers & PIPE_CLEAR_COLOR) { int num_buffers = ctx->Extensions.EXT_draw_buffers2 ? ctx->DrawBuffer->_NumColorDrawBuffers : 1; int i; blend.independent_blend_enable = num_buffers > 1; for (i = 0; i < num_buffers; i++) { if (!(clear_buffers & (PIPE_CLEAR_COLOR0 << i))) continue; if (ctx->Color.ColorMask[i][0]) blend.rt[i].colormask |= PIPE_MASK_R; if (ctx->Color.ColorMask[i][1]) blend.rt[i].colormask |= PIPE_MASK_G; if (ctx->Color.ColorMask[i][2]) blend.rt[i].colormask |= PIPE_MASK_B; if (ctx->Color.ColorMask[i][3]) blend.rt[i].colormask |= PIPE_MASK_A; } if (st->ctx->Color.DitherFlag) blend.dither = 1; } cso_set_blend(st->cso_context, &blend); } /* depth_stencil state: always pass/set to ref value */ { struct pipe_depth_stencil_alpha_state depth_stencil; memset(&depth_stencil, 0, sizeof(depth_stencil)); if (clear_buffers & PIPE_CLEAR_DEPTH) { depth_stencil.depth.enabled = 1; depth_stencil.depth.writemask = 1; depth_stencil.depth.func = PIPE_FUNC_ALWAYS; } if (clear_buffers & PIPE_CLEAR_STENCIL) { struct pipe_stencil_ref stencil_ref; memset(&stencil_ref, 0, sizeof(stencil_ref)); depth_stencil.stencil[0].enabled = 1; depth_stencil.stencil[0].func = PIPE_FUNC_ALWAYS; depth_stencil.stencil[0].fail_op = PIPE_STENCIL_OP_REPLACE; depth_stencil.stencil[0].zpass_op = PIPE_STENCIL_OP_REPLACE; depth_stencil.stencil[0].zfail_op = PIPE_STENCIL_OP_REPLACE; depth_stencil.stencil[0].valuemask = 0xff; depth_stencil.stencil[0].writemask = ctx->Stencil.WriteMask[0] & 0xff; stencil_ref.ref_value[0] = ctx->Stencil.Clear; cso_set_stencil_ref(st->cso_context, &stencil_ref); } cso_set_depth_stencil_alpha(st->cso_context, &depth_stencil); } cso_set_vertex_elements(st->cso_context, 2, st->velems_util_draw); cso_set_stream_outputs(st->cso_context, 0, NULL, NULL); cso_set_sample_mask(st->cso_context, ~0); cso_set_rasterizer(st->cso_context, &st->clear.raster); /* viewport state: viewport matching window dims */ { const GLboolean invert = (st_fb_orientation(fb) == Y_0_TOP); struct pipe_viewport_state vp; vp.scale[0] = 0.5f * fb_width; vp.scale[1] = fb_height * (invert ? -0.5f : 0.5f); 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(st->cso_context, &vp); } set_fragment_shader(st); cso_set_geometry_shader_handle(st->cso_context, NULL); if (num_layers > 1) set_vertex_shader_layered(st); else set_vertex_shader(st); /* We can't translate the clear color to the colorbuffer format, * because different colorbuffers may have different formats. */ /* draw quad matching scissor rect */ draw_quad(st, x0, y0, x1, y1, (GLfloat) ctx->Depth.Clear, num_layers, (union pipe_color_union*)&ctx->Color.ClearColor); /* Restore pipe state */ cso_restore_blend(st->cso_context); cso_restore_stencil_ref(st->cso_context); cso_restore_depth_stencil_alpha(st->cso_context); cso_restore_rasterizer(st->cso_context); cso_restore_sample_mask(st->cso_context); cso_restore_viewport(st->cso_context); cso_restore_fragment_shader(st->cso_context); cso_restore_vertex_shader(st->cso_context); cso_restore_geometry_shader(st->cso_context); cso_restore_vertex_elements(st->cso_context); cso_restore_aux_vertex_buffer_slot(st->cso_context); cso_restore_stream_outputs(st->cso_context); }
static void st_BlitFramebuffer(struct gl_context *ctx, GLint srcX0, GLint srcY0, GLint srcX1, GLint srcY1, GLint dstX0, GLint dstY0, GLint dstX1, GLint dstY1, GLbitfield mask, GLenum filter) { const GLbitfield depthStencil = (GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT); struct st_context *st = st_context(ctx); const uint pFilter = ((filter == GL_NEAREST) ? PIPE_TEX_MIPFILTER_NEAREST : PIPE_TEX_MIPFILTER_LINEAR); struct gl_framebuffer *readFB = ctx->ReadBuffer; struct gl_framebuffer *drawFB = ctx->DrawBuffer; st_validate_state(st); if (!_mesa_clip_blit(ctx, &srcX0, &srcY0, &srcX1, &srcY1, &dstX0, &dstY0, &dstX1, &dstY1)) { return; /* nothing to draw/blit */ } if (st_fb_orientation(drawFB) == Y_0_TOP) { /* invert Y for dest */ dstY0 = drawFB->Height - dstY0; dstY1 = drawFB->Height - dstY1; } if (st_fb_orientation(readFB) == Y_0_TOP) { /* invert Y for src */ srcY0 = readFB->Height - srcY0; srcY1 = readFB->Height - srcY1; } /* Disable conditional rendering. */ if (st->render_condition) { st->pipe->render_condition(st->pipe, NULL, 0); } if (readFB->Visual.sampleBuffers > drawFB->Visual.sampleBuffers && readFB->Visual.samples > 1) { struct pipe_resolve_info info; if (dstX0 < dstX1) { info.dst.x0 = dstX0; info.dst.x1 = dstX1; info.src.x0 = srcX0; info.src.x1 = srcX1; } else { info.dst.x0 = dstX1; info.dst.x1 = dstX0; info.src.x0 = srcX1; info.src.x1 = srcX0; } if (dstY0 < dstY1) { info.dst.y0 = dstY0; info.dst.y1 = dstY1; info.src.y0 = srcY0; info.src.y1 = srcY1; } else { info.dst.y0 = dstY1; info.dst.y1 = dstY0; info.src.y0 = srcY1; info.src.y1 = srcY0; } st_BlitFramebuffer_resolve(ctx, mask, &info); /* filter doesn't apply */ goto done; } if (srcY0 > srcY1 && dstY0 > dstY1) { /* Both src and dst are upside down. Swap Y to make it * right-side up to increase odds of using a fast path. * Recall that all Gallium raster coords have Y=0=top. */ GLint tmp; tmp = srcY0; srcY0 = srcY1; srcY1 = tmp; tmp = dstY0; dstY0 = dstY1; dstY1 = tmp; } if (mask & GL_COLOR_BUFFER_BIT) { struct gl_renderbuffer_attachment *srcAtt = &readFB->Attachment[readFB->_ColorReadBufferIndex]; if(srcAtt->Type == GL_TEXTURE) { struct st_texture_object *srcObj = st_texture_object(srcAtt->Texture); struct st_renderbuffer *dstRb = st_renderbuffer(drawFB->_ColorDrawBuffers[0]); struct pipe_surface *dstSurf = dstRb->surface; if (!srcObj->pt) goto done; util_blit_pixels(st->blit, srcObj->pt, srcAtt->TextureLevel, srcX0, srcY0, srcX1, srcY1, srcAtt->Zoffset + srcAtt->CubeMapFace, dstSurf, dstX0, dstY0, dstX1, dstY1, 0.0, pFilter, TGSI_WRITEMASK_XYZW, 0); } else { struct st_renderbuffer *srcRb = st_renderbuffer(readFB->_ColorReadBuffer); struct st_renderbuffer *dstRb = st_renderbuffer(drawFB->_ColorDrawBuffers[0]); struct pipe_surface *srcSurf = srcRb->surface; struct pipe_surface *dstSurf = dstRb->surface; util_blit_pixels(st->blit, srcRb->texture, srcSurf->u.tex.level, srcX0, srcY0, srcX1, srcY1, srcSurf->u.tex.first_layer, dstSurf, dstX0, dstY0, dstX1, dstY1, 0.0, pFilter, TGSI_WRITEMASK_XYZW, 0); } } if (mask & depthStencil) { /* depth and/or stencil blit */ /* get src/dst depth surfaces */ struct gl_renderbuffer_attachment *srcDepth = &readFB->Attachment[BUFFER_DEPTH]; struct gl_renderbuffer_attachment *dstDepth = &drawFB->Attachment[BUFFER_DEPTH]; struct gl_renderbuffer_attachment *srcStencil = &readFB->Attachment[BUFFER_STENCIL]; struct gl_renderbuffer_attachment *dstStencil = &drawFB->Attachment[BUFFER_STENCIL]; struct st_renderbuffer *srcDepthRb = st_renderbuffer(readFB->Attachment[BUFFER_DEPTH].Renderbuffer); struct st_renderbuffer *dstDepthRb = st_renderbuffer(drawFB->Attachment[BUFFER_DEPTH].Renderbuffer); struct pipe_surface *dstDepthSurf = dstDepthRb ? dstDepthRb->surface : NULL; struct st_renderbuffer *srcStencilRb = st_renderbuffer(readFB->Attachment[BUFFER_STENCIL].Renderbuffer); struct st_renderbuffer *dstStencilRb = st_renderbuffer(drawFB->Attachment[BUFFER_STENCIL].Renderbuffer); struct pipe_surface *dstStencilSurf = dstStencilRb ? dstStencilRb->surface : NULL; if ((mask & depthStencil) == depthStencil && st_is_depth_stencil_combined(srcDepth, srcStencil) && st_is_depth_stencil_combined(dstDepth, dstStencil)) { /* Blitting depth and stencil values between combined * depth/stencil buffers. This is the ideal case for such buffers. */ util_blit_pixels(st->blit, srcDepthRb->texture, srcDepthRb->surface->u.tex.level, srcX0, srcY0, srcX1, srcY1, srcDepthRb->surface->u.tex.first_layer, dstDepthSurf, dstX0, dstY0, dstX1, dstY1, 0.0, pFilter, 0, BLIT_WRITEMASK_Z | (st->has_stencil_export ? BLIT_WRITEMASK_STENCIL : 0)); if (!st->has_stencil_export) { _mesa_problem(ctx, "st_BlitFramebuffer(STENCIL) " "software fallback not implemented"); } } else { /* blitting depth and stencil separately */ if (mask & GL_DEPTH_BUFFER_BIT) { util_blit_pixels(st->blit, srcDepthRb->texture, srcDepthRb->surface->u.tex.level, srcX0, srcY0, srcX1, srcY1, srcDepthRb->surface->u.tex.first_layer, dstDepthSurf, dstX0, dstY0, dstX1, dstY1, 0.0, pFilter, 0, BLIT_WRITEMASK_Z); } if (mask & GL_STENCIL_BUFFER_BIT) { if (st->has_stencil_export) { util_blit_pixels(st->blit, srcStencilRb->texture, srcStencilRb->surface->u.tex.level, srcX0, srcY0, srcX1, srcY1, srcStencilRb->surface->u.tex.first_layer, dstStencilSurf, dstX0, dstY0, dstX1, dstY1, 0.0, pFilter, 0, BLIT_WRITEMASK_STENCIL); } else { _mesa_problem(ctx, "st_BlitFramebuffer(STENCIL) " "software fallback not implemented"); } } } } done: /* Restore conditional rendering state. */ if (st->render_condition) { st->pipe->render_condition(st->pipe, st->render_condition, st->condition_mode); } }
static void st_BlitFramebuffer(struct gl_context *ctx, struct gl_framebuffer *readFB, struct gl_framebuffer *drawFB, GLint srcX0, GLint srcY0, GLint srcX1, GLint srcY1, GLint dstX0, GLint dstY0, GLint dstX1, GLint dstY1, GLbitfield mask, GLenum filter) { const GLbitfield depthStencil = (GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT); struct st_context *st = st_context(ctx); const uint pFilter = ((filter == GL_NEAREST) ? PIPE_TEX_FILTER_NEAREST : PIPE_TEX_FILTER_LINEAR); struct { GLint srcX0, srcY0, srcX1, srcY1; GLint dstX0, dstY0, dstX1, dstY1; } clip; struct pipe_blit_info blit; st_manager_validate_framebuffers(st); /* Make sure bitmap rendering has landed in the framebuffers */ st_flush_bitmap_cache(st); st_invalidate_readpix_cache(st); clip.srcX0 = srcX0; clip.srcY0 = srcY0; clip.srcX1 = srcX1; clip.srcY1 = srcY1; clip.dstX0 = dstX0; clip.dstY0 = dstY0; clip.dstX1 = dstX1; clip.dstY1 = dstY1; /* NOTE: If the src and dst dimensions don't match, we cannot simply adjust * the integer coordinates to account for clipping (or scissors) because that * would make us cut off fractional parts, affecting the result of the blit. * * XXX: This should depend on mask ! */ if (!_mesa_clip_blit(ctx, readFB, drawFB, &clip.srcX0, &clip.srcY0, &clip.srcX1, &clip.srcY1, &clip.dstX0, &clip.dstY0, &clip.dstX1, &clip.dstY1)) { return; /* nothing to draw/blit */ } memset(&blit, 0, sizeof(struct pipe_blit_info)); blit.scissor_enable = (dstX0 != clip.dstX0) || (dstY0 != clip.dstY0) || (dstX1 != clip.dstX1) || (dstY1 != clip.dstY1); if (st_fb_orientation(drawFB) == Y_0_TOP) { /* invert Y for dest */ dstY0 = drawFB->Height - dstY0; dstY1 = drawFB->Height - dstY1; /* invert Y for clip */ clip.dstY0 = drawFB->Height - clip.dstY0; clip.dstY1 = drawFB->Height - clip.dstY1; } if (blit.scissor_enable) { blit.scissor.minx = MIN2(clip.dstX0, clip.dstX1); blit.scissor.miny = MIN2(clip.dstY0, clip.dstY1); blit.scissor.maxx = MAX2(clip.dstX0, clip.dstX1); blit.scissor.maxy = MAX2(clip.dstY0, clip.dstY1); #if 0 debug_printf("scissor = (%i,%i)-(%i,%i)\n", blit.scissor.minx,blit.scissor.miny, blit.scissor.maxx,blit.scissor.maxy); #endif } if (st_fb_orientation(readFB) == Y_0_TOP) { /* invert Y for src */ srcY0 = readFB->Height - srcY0; srcY1 = readFB->Height - srcY1; } if (srcY0 > srcY1 && dstY0 > dstY1) { /* Both src and dst are upside down. Swap Y to make it * right-side up to increase odds of using a fast path. * Recall that all Gallium raster coords have Y=0=top. */ GLint tmp; tmp = srcY0; srcY0 = srcY1; srcY1 = tmp; tmp = dstY0; dstY0 = dstY1; dstY1 = tmp; } blit.src.box.depth = 1; blit.dst.box.depth = 1; /* Destination dimensions have to be positive: */ if (dstX0 < dstX1) { blit.dst.box.x = dstX0; blit.src.box.x = srcX0; blit.dst.box.width = dstX1 - dstX0; blit.src.box.width = srcX1 - srcX0; } else { blit.dst.box.x = dstX1; blit.src.box.x = srcX1; blit.dst.box.width = dstX0 - dstX1; blit.src.box.width = srcX0 - srcX1; } if (dstY0 < dstY1) { blit.dst.box.y = dstY0; blit.src.box.y = srcY0; blit.dst.box.height = dstY1 - dstY0; blit.src.box.height = srcY1 - srcY0; } else { blit.dst.box.y = dstY1; blit.src.box.y = srcY1; blit.dst.box.height = dstY0 - dstY1; blit.src.box.height = srcY0 - srcY1; } if (drawFB != ctx->WinSysDrawBuffer) st_window_rectangles_to_blit(ctx, &blit); blit.filter = pFilter; blit.render_condition_enable = TRUE; blit.alpha_blend = FALSE; if (mask & GL_COLOR_BUFFER_BIT) { struct gl_renderbuffer_attachment *srcAtt = &readFB->Attachment[readFB->_ColorReadBufferIndex]; blit.mask = PIPE_MASK_RGBA; if (srcAtt->Type == GL_TEXTURE) { struct st_texture_object *srcObj = st_texture_object(srcAtt->Texture); GLuint i; if (!srcObj || !srcObj->pt) { return; } for (i = 0; i < drawFB->_NumColorDrawBuffers; i++) { struct st_renderbuffer *dstRb = st_renderbuffer(drawFB->_ColorDrawBuffers[i]); if (dstRb) { struct pipe_surface *dstSurf = dstRb->surface; if (dstSurf) { blit.dst.resource = dstSurf->texture; blit.dst.level = dstSurf->u.tex.level; blit.dst.box.z = dstSurf->u.tex.first_layer; blit.dst.format = dstSurf->format; blit.src.resource = srcObj->pt; blit.src.level = srcAtt->TextureLevel; blit.src.box.z = srcAtt->Zoffset + srcAtt->CubeMapFace; blit.src.format = srcObj->pt->format; st_adjust_blit_for_srgb(&blit, ctx->Color.sRGBEnabled); st->pipe->blit(st->pipe, &blit); dstRb->defined = true; /* front buffer tracking */ } } } } else { struct st_renderbuffer *srcRb = st_renderbuffer(readFB->_ColorReadBuffer); struct pipe_surface *srcSurf; GLuint i; if (!srcRb || !srcRb->surface) { return; } srcSurf = srcRb->surface; for (i = 0; i < drawFB->_NumColorDrawBuffers; i++) { struct st_renderbuffer *dstRb = st_renderbuffer(drawFB->_ColorDrawBuffers[i]); if (dstRb) { struct pipe_surface *dstSurf = dstRb->surface; if (dstSurf) { blit.dst.resource = dstSurf->texture; blit.dst.level = dstSurf->u.tex.level; blit.dst.box.z = dstSurf->u.tex.first_layer; blit.dst.format = dstSurf->format; blit.src.resource = srcSurf->texture; blit.src.level = srcSurf->u.tex.level; blit.src.box.z = srcSurf->u.tex.first_layer; blit.src.format = srcSurf->format; st_adjust_blit_for_srgb(&blit, ctx->Color.sRGBEnabled); st->pipe->blit(st->pipe, &blit); dstRb->defined = true; /* front buffer tracking */ } } } } } if (mask & depthStencil) { /* depth and/or stencil blit */ /* get src/dst depth surfaces */ struct st_renderbuffer *srcDepthRb = st_renderbuffer(readFB->Attachment[BUFFER_DEPTH].Renderbuffer); struct st_renderbuffer *dstDepthRb = st_renderbuffer(drawFB->Attachment[BUFFER_DEPTH].Renderbuffer); struct pipe_surface *dstDepthSurf = dstDepthRb ? dstDepthRb->surface : NULL; struct st_renderbuffer *srcStencilRb = st_renderbuffer(readFB->Attachment[BUFFER_STENCIL].Renderbuffer); struct st_renderbuffer *dstStencilRb = st_renderbuffer(drawFB->Attachment[BUFFER_STENCIL].Renderbuffer); struct pipe_surface *dstStencilSurf = dstStencilRb ? dstStencilRb->surface : NULL; if (_mesa_has_depthstencil_combined(readFB) && _mesa_has_depthstencil_combined(drawFB)) { blit.mask = 0; if (mask & GL_DEPTH_BUFFER_BIT) blit.mask |= PIPE_MASK_Z; if (mask & GL_STENCIL_BUFFER_BIT) blit.mask |= PIPE_MASK_S; blit.dst.resource = dstDepthSurf->texture; blit.dst.level = dstDepthSurf->u.tex.level; blit.dst.box.z = dstDepthSurf->u.tex.first_layer; blit.dst.format = dstDepthSurf->format; blit.src.resource = srcDepthRb->texture; blit.src.level = srcDepthRb->surface->u.tex.level; blit.src.box.z = srcDepthRb->surface->u.tex.first_layer; blit.src.format = srcDepthRb->surface->format; st->pipe->blit(st->pipe, &blit); } else { /* blitting depth and stencil separately */ if (mask & GL_DEPTH_BUFFER_BIT) { blit.mask = PIPE_MASK_Z; blit.dst.resource = dstDepthSurf->texture; blit.dst.level = dstDepthSurf->u.tex.level; blit.dst.box.z = dstDepthSurf->u.tex.first_layer; blit.dst.format = dstDepthSurf->format; blit.src.resource = srcDepthRb->texture; blit.src.level = srcDepthRb->surface->u.tex.level; blit.src.box.z = srcDepthRb->surface->u.tex.first_layer; blit.src.format = srcDepthRb->surface->format; st->pipe->blit(st->pipe, &blit); } if (mask & GL_STENCIL_BUFFER_BIT) { blit.mask = PIPE_MASK_S; blit.dst.resource = dstStencilSurf->texture; blit.dst.level = dstStencilSurf->u.tex.level; blit.dst.box.z = dstStencilSurf->u.tex.first_layer; blit.dst.format = dstStencilSurf->format; blit.src.resource = srcStencilRb->texture; blit.src.level = srcStencilRb->surface->u.tex.level; blit.src.box.z = srcStencilRb->surface->u.tex.first_layer; blit.src.format = srcStencilRb->surface->format; st->pipe->blit(st->pipe, &blit); } } } }
/** * Do a CopyTexSubImage operation using a read transfer from the source, * a write transfer to the destination and get_tile()/put_tile() to access * the pixels/texels. * * Note: srcY=0=TOP of renderbuffer */ static void fallback_copy_texsubimage(struct gl_context *ctx, struct st_renderbuffer *strb, struct st_texture_image *stImage, GLenum baseFormat, GLint destX, GLint destY, GLint destZ, GLint srcX, GLint srcY, GLsizei width, GLsizei height) { struct st_context *st = st_context(ctx); struct pipe_context *pipe = st->pipe; struct pipe_transfer *src_trans; GLvoid *texDest; enum pipe_transfer_usage transfer_usage; void *map; if (ST_DEBUG & DEBUG_FALLBACK) debug_printf("%s: fallback processing\n", __FUNCTION__); if (st_fb_orientation(ctx->ReadBuffer) == Y_0_TOP) { srcY = strb->Base.Height - srcY - height; } map = pipe_transfer_map(pipe, strb->texture, strb->rtt_level, strb->rtt_face + strb->rtt_slice, PIPE_TRANSFER_READ, srcX, srcY, width, height, &src_trans); if ((baseFormat == GL_DEPTH_COMPONENT || baseFormat == GL_DEPTH_STENCIL) && util_format_is_depth_and_stencil(stImage->pt->format)) transfer_usage = PIPE_TRANSFER_READ_WRITE; else transfer_usage = PIPE_TRANSFER_WRITE; /* XXX this used to ignore destZ param */ texDest = st_texture_image_map(st, stImage, destZ, transfer_usage, destX, destY, width, height); if (baseFormat == GL_DEPTH_COMPONENT || baseFormat == GL_DEPTH_STENCIL) { const GLboolean scaleOrBias = (ctx->Pixel.DepthScale != 1.0F || ctx->Pixel.DepthBias != 0.0F); GLint row, yStep; uint *data; /* determine bottom-to-top vs. top-to-bottom order for src buffer */ if (st_fb_orientation(ctx->ReadBuffer) == Y_0_TOP) { srcY = height - 1; yStep = -1; } else { srcY = 0; yStep = 1; } data = malloc(width * sizeof(uint)); if (data) { /* To avoid a large temp memory allocation, do copy row by row */ for (row = 0; row < height; row++, srcY += yStep) { pipe_get_tile_z(src_trans, map, 0, srcY, width, 1, data); if (scaleOrBias) { _mesa_scale_and_bias_depth_uint(ctx, width, data); } pipe_put_tile_z(stImage->transfer, texDest, 0, row, width, 1, data); } } else { _mesa_error(ctx, GL_OUT_OF_MEMORY, "glCopyTexSubImage()"); } free(data); } else { /* RGBA format */ GLfloat *tempSrc = malloc(width * height * 4 * sizeof(GLfloat)); if (tempSrc && texDest) { const GLint dims = 2; const GLint dstRowStride = stImage->transfer->stride; struct gl_texture_image *texImage = &stImage->base; struct gl_pixelstore_attrib unpack = ctx->DefaultPacking; if (st_fb_orientation(ctx->ReadBuffer) == Y_0_TOP) { unpack.Invert = GL_TRUE; } /* get float/RGBA image from framebuffer */ /* XXX this usually involves a lot of int/float conversion. * try to avoid that someday. */ pipe_get_tile_rgba_format(src_trans, map, 0, 0, width, height, util_format_linear(strb->texture->format), tempSrc); /* Store into texture memory. * Note that this does some special things such as pixel transfer * ops and format conversion. In particular, if the dest tex format * is actually RGBA but the user created the texture as GL_RGB we * need to fill-in/override the alpha channel with 1.0. */ _mesa_texstore(ctx, dims, texImage->_BaseFormat, texImage->TexFormat, dstRowStride, (GLubyte **) &texDest, width, height, 1, GL_RGBA, GL_FLOAT, tempSrc, /* src */ &unpack); } else { _mesa_error(ctx, GL_OUT_OF_MEMORY, "glTexSubImage"); } free(tempSrc); } st_texture_image_unmap(st, stImage); pipe->transfer_unmap(pipe, src_trans); }
/** * This uses a blit to copy the read buffer to a texture format which matches * the format and type combo and then a fast read-back is done using memcpy. * We can do arbitrary X/Y/Z/W/0/1 swizzling here as long as there is * a format which matches the swizzling. * * If such a format isn't available, we fall back to _mesa_readpixels. * * NOTE: Some drivers use a blit to convert between tiled and linear * texture layouts during texture uploads/downloads, so the blit * we do here should be free in such cases. */ static void st_readpixels(struct gl_context *ctx, GLint x, GLint y, GLsizei width, GLsizei height, GLenum format, GLenum type, const struct gl_pixelstore_attrib *pack, GLvoid *pixels) { struct st_context *st = st_context(ctx); struct gl_renderbuffer *rb = _mesa_get_read_renderbuffer_for_format(ctx, format); struct st_renderbuffer *strb = st_renderbuffer(rb); struct pipe_context *pipe = st->pipe; struct pipe_screen *screen = pipe->screen; struct pipe_resource *src; struct pipe_resource *dst = NULL; struct pipe_resource dst_templ; enum pipe_format dst_format, src_format; struct pipe_blit_info blit; unsigned bind = PIPE_BIND_TRANSFER_READ; struct pipe_transfer *tex_xfer; ubyte *map = NULL; /* Validate state (to be sure we have up-to-date framebuffer surfaces) * and flush the bitmap cache prior to reading. */ st_validate_state(st); st_flush_bitmap_cache(st); if (!st->prefer_blit_based_texture_transfer) { goto fallback; } /* This must be done after state validation. */ src = strb->texture; /* XXX Fallback for depth-stencil formats due to an incomplete * stencil blit implementation in some drivers. */ if (format == GL_DEPTH_STENCIL) { goto fallback; } /* We are creating a texture of the size of the region being read back. * Need to check for NPOT texture support. */ if (!screen->get_param(screen, PIPE_CAP_NPOT_TEXTURES) && (!util_is_power_of_two(width) || !util_is_power_of_two(height))) { goto fallback; } /* If the base internal format and the texture format don't match, we have * to use the slow path. */ if (rb->_BaseFormat != _mesa_get_format_base_format(rb->Format)) { goto fallback; } /* See if the texture format already matches the format and type, * in which case the memcpy-based fast path will likely be used and * we don't have to blit. */ if (_mesa_format_matches_format_and_type(rb->Format, format, type, pack->SwapBytes)) { goto fallback; } if (_mesa_readpixels_needs_slow_path(ctx, format, type, GL_TRUE)) { goto fallback; } /* Convert the source format to what is expected by ReadPixels * and see if it's supported. */ src_format = util_format_linear(src->format); src_format = util_format_luminance_to_red(src_format); src_format = util_format_intensity_to_red(src_format); if (!src_format || !screen->is_format_supported(screen, src_format, src->target, src->nr_samples, PIPE_BIND_SAMPLER_VIEW)) { goto fallback; } if (format == GL_DEPTH_COMPONENT || format == GL_DEPTH_STENCIL) bind |= PIPE_BIND_DEPTH_STENCIL; else bind |= PIPE_BIND_RENDER_TARGET; /* Choose the destination format by finding the best match * for the format+type combo. */ dst_format = st_choose_matching_format(screen, bind, format, type, pack->SwapBytes); if (dst_format == PIPE_FORMAT_NONE) { goto fallback; } /* create the destination texture */ memset(&dst_templ, 0, sizeof(dst_templ)); dst_templ.target = PIPE_TEXTURE_2D; dst_templ.format = dst_format; dst_templ.bind = bind; dst_templ.usage = PIPE_USAGE_STAGING; st_gl_texture_dims_to_pipe_dims(GL_TEXTURE_2D, width, height, 1, &dst_templ.width0, &dst_templ.height0, &dst_templ.depth0, &dst_templ.array_size); dst = screen->resource_create(screen, &dst_templ); if (!dst) { goto fallback; } memset(&blit, 0, sizeof(blit)); blit.src.resource = src; blit.src.level = strb->surface->u.tex.level; blit.src.format = src_format; blit.dst.resource = dst; blit.dst.level = 0; blit.dst.format = dst->format; blit.src.box.x = x; blit.dst.box.x = 0; blit.src.box.y = y; blit.dst.box.y = 0; blit.src.box.z = strb->surface->u.tex.first_layer; blit.dst.box.z = 0; blit.src.box.width = blit.dst.box.width = width; blit.src.box.height = blit.dst.box.height = height; blit.src.box.depth = blit.dst.box.depth = 1; blit.mask = st_get_blit_mask(rb->_BaseFormat, format); blit.filter = PIPE_TEX_FILTER_NEAREST; blit.scissor_enable = FALSE; if (st_fb_orientation(ctx->ReadBuffer) == Y_0_TOP) { blit.src.box.y = rb->Height - blit.src.box.y; blit.src.box.height = -blit.src.box.height; } /* blit */ st->pipe->blit(st->pipe, &blit); /* map resources */ pixels = _mesa_map_pbo_dest(ctx, pack, pixels); map = pipe_transfer_map_3d(pipe, dst, 0, PIPE_TRANSFER_READ, 0, 0, 0, width, height, 1, &tex_xfer); if (!map) { _mesa_unmap_pbo_dest(ctx, pack); pipe_resource_reference(&dst, NULL); goto fallback; } /* memcpy data into a user buffer */ { const uint bytesPerRow = width * util_format_get_blocksize(dst_format); GLuint row; for (row = 0; row < (unsigned) height; row++) { GLvoid *dest = _mesa_image_address3d(pack, pixels, width, height, format, type, 0, row, 0); memcpy(dest, map, bytesPerRow); map += tex_xfer->stride; } } pipe_transfer_unmap(pipe, tex_xfer); _mesa_unmap_pbo_dest(ctx, pack); pipe_resource_reference(&dst, NULL); return; fallback: _mesa_readpixels(ctx, x, y, width, height, format, type, pack, pixels); }
/** * Do glClear by drawing a quadrilateral. * The vertices of the quad will be computed from the * ctx->DrawBuffer->_X/Ymin/max fields. */ static void clear_with_quad(struct gl_context *ctx, unsigned clear_buffers) { struct st_context *st = st_context(ctx); struct cso_context *cso = st->cso_context; const struct gl_framebuffer *fb = ctx->DrawBuffer; const GLfloat fb_width = (GLfloat) fb->Width; const GLfloat fb_height = (GLfloat) fb->Height; const GLfloat x0 = (GLfloat) ctx->DrawBuffer->_Xmin / fb_width * 2.0f - 1.0f; const GLfloat x1 = (GLfloat) ctx->DrawBuffer->_Xmax / fb_width * 2.0f - 1.0f; const GLfloat y0 = (GLfloat) ctx->DrawBuffer->_Ymin / fb_height * 2.0f - 1.0f; const GLfloat y1 = (GLfloat) ctx->DrawBuffer->_Ymax / fb_height * 2.0f - 1.0f; unsigned num_layers = util_framebuffer_get_num_layers(&st->state.framebuffer); /* printf("%s %s%s%s %f,%f %f,%f\n", __func__, color ? "color, " : "", depth ? "depth, " : "", stencil ? "stencil" : "", x0, y0, x1, y1); */ cso_save_state(cso, (CSO_BIT_BLEND | CSO_BIT_STENCIL_REF | CSO_BIT_DEPTH_STENCIL_ALPHA | CSO_BIT_RASTERIZER | CSO_BIT_SAMPLE_MASK | CSO_BIT_MIN_SAMPLES | CSO_BIT_VIEWPORT | CSO_BIT_STREAM_OUTPUTS | CSO_BIT_VERTEX_ELEMENTS | CSO_BIT_AUX_VERTEX_BUFFER_SLOT | CSO_BIT_PAUSE_QUERIES | CSO_BITS_ALL_SHADERS)); /* blend state: RGBA masking */ { struct pipe_blend_state blend; memset(&blend, 0, sizeof(blend)); if (clear_buffers & PIPE_CLEAR_COLOR) { int num_buffers = ctx->Extensions.EXT_draw_buffers2 ? ctx->DrawBuffer->_NumColorDrawBuffers : 1; int i; blend.independent_blend_enable = num_buffers > 1; for (i = 0; i < num_buffers; i++) { if (!(clear_buffers & (PIPE_CLEAR_COLOR0 << i))) continue; if (ctx->Color.ColorMask[i][0]) blend.rt[i].colormask |= PIPE_MASK_R; if (ctx->Color.ColorMask[i][1]) blend.rt[i].colormask |= PIPE_MASK_G; if (ctx->Color.ColorMask[i][2]) blend.rt[i].colormask |= PIPE_MASK_B; if (ctx->Color.ColorMask[i][3]) blend.rt[i].colormask |= PIPE_MASK_A; } if (ctx->Color.DitherFlag) blend.dither = 1; } cso_set_blend(cso, &blend); } /* depth_stencil state: always pass/set to ref value */ { struct pipe_depth_stencil_alpha_state depth_stencil; memset(&depth_stencil, 0, sizeof(depth_stencil)); if (clear_buffers & PIPE_CLEAR_DEPTH) { depth_stencil.depth.enabled = 1; depth_stencil.depth.writemask = 1; depth_stencil.depth.func = PIPE_FUNC_ALWAYS; } if (clear_buffers & PIPE_CLEAR_STENCIL) { struct pipe_stencil_ref stencil_ref; memset(&stencil_ref, 0, sizeof(stencil_ref)); depth_stencil.stencil[0].enabled = 1; depth_stencil.stencil[0].func = PIPE_FUNC_ALWAYS; depth_stencil.stencil[0].fail_op = PIPE_STENCIL_OP_REPLACE; depth_stencil.stencil[0].zpass_op = PIPE_STENCIL_OP_REPLACE; depth_stencil.stencil[0].zfail_op = PIPE_STENCIL_OP_REPLACE; depth_stencil.stencil[0].valuemask = 0xff; depth_stencil.stencil[0].writemask = ctx->Stencil.WriteMask[0] & 0xff; stencil_ref.ref_value[0] = ctx->Stencil.Clear; cso_set_stencil_ref(cso, &stencil_ref); } cso_set_depth_stencil_alpha(cso, &depth_stencil); } cso_set_vertex_elements(cso, 2, st->util_velems); cso_set_stream_outputs(cso, 0, NULL, NULL); cso_set_sample_mask(cso, ~0); cso_set_min_samples(cso, 1); cso_set_rasterizer(cso, &st->clear.raster); /* viewport state: viewport matching window dims */ cso_set_viewport_dims(st->cso_context, fb_width, fb_height, st_fb_orientation(fb) == Y_0_TOP); set_fragment_shader(st); cso_set_tessctrl_shader_handle(cso, NULL); cso_set_tesseval_shader_handle(cso, NULL); if (num_layers > 1) set_vertex_shader_layered(st); else set_vertex_shader(st); /* draw quad matching scissor rect. * * Note: if we're only clearing depth/stencil we still setup vertices * with color, but they'll be ignored. * * We can't translate the clear color to the colorbuffer format, * because different colorbuffers may have different formats. */ if (!st_draw_quad(st, x0, y0, x1, y1, ctx->Depth.Clear * 2.0f - 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, (const float *) &ctx->Color.ClearColor.f, num_layers)) { _mesa_error(ctx, GL_OUT_OF_MEMORY, "glClear"); } /* Restore pipe state */ cso_restore_state(cso); }