#include "main/mfeatures.h"
#include "main/mtypes.h"
#include "main/pack.h"
+#include "main/pbo.h"
#include "main/texformat.h"
+#include "main/teximage.h"
#include "main/texstore.h"
#include "program/program.h"
#include "program/prog_print.h"
}
+/**
+ * Returns a fragment program which implements the current pixel transfer ops.
+ */
+static struct gl_fragment_program *
+get_glsl_pixel_transfer_program(struct st_context *st,
+ struct st_fragment_program *orig)
+{
+ int pixelMaps = 0, scaleAndBias = 0;
+ struct gl_context *ctx = st->ctx;
+ struct st_fragment_program *fp = (struct st_fragment_program *)
+ ctx->Driver.NewProgram(ctx, GL_FRAGMENT_PROGRAM_ARB, 0);
+
+ if (!fp)
+ return NULL;
+
+ if (ctx->Pixel.RedBias != 0.0 || ctx->Pixel.RedScale != 1.0 ||
+ ctx->Pixel.GreenBias != 0.0 || ctx->Pixel.GreenScale != 1.0 ||
+ ctx->Pixel.BlueBias != 0.0 || ctx->Pixel.BlueScale != 1.0 ||
+ ctx->Pixel.AlphaBias != 0.0 || ctx->Pixel.AlphaScale != 1.0) {
+ scaleAndBias = 1;
+ }
+
+ pixelMaps = ctx->Pixel.MapColorFlag;
+
+ if (pixelMaps) {
+ /* create the colormap/texture now if not already done */
+ if (!st->pixel_xfer.pixelmap_texture) {
+ st->pixel_xfer.pixelmap_texture = st_create_color_map_texture(ctx);
+ st->pixel_xfer.pixelmap_sampler_view =
+ st_create_texture_sampler_view(st->pipe,
+ st->pixel_xfer.pixelmap_texture);
+ }
+ }
+
+ get_pixel_transfer_visitor(fp, orig->glsl_to_tgsi,
+ scaleAndBias, pixelMaps);
+
+ return &fp->Base;
+}
+
/**
* Make fragment shader for glDraw/CopyPixels. This shader is made
struct gl_fragment_program **fpOut)
{
struct gl_program *newProg;
+ struct st_fragment_program *stfp = (struct st_fragment_program *) fpIn;
if (is_passthrough_program(fpIn)) {
newProg = (struct gl_program *) _mesa_clone_fragment_program(st->ctx,
&st->pixel_xfer.program->Base);
}
+ else if (stfp->glsl_to_tgsi != NULL) {
+ newProg = (struct gl_program *) get_glsl_pixel_transfer_program(st, stfp);
+ }
else {
#if 0
/* debug */
p->InputsRead = FRAG_BIT_TEX0 | FRAG_BIT_COL0;
p->OutputsWritten = 0;
if (write_depth)
- p->OutputsWritten |= (1 << FRAG_RESULT_DEPTH);
+ p->OutputsWritten |= BITFIELD64_BIT(FRAG_RESULT_DEPTH);
if (write_stencil)
- p->OutputsWritten |= (1 << FRAG_RESULT_STENCIL);
+ p->OutputsWritten |= BITFIELD64_BIT(FRAG_RESULT_STENCIL);
p->SamplersUsed = 0x1; /* sampler 0 (bit 0) is used */
if (write_stencil)
}
-/**
- * Return a texture base format for drawing/copying an image
- * of the given format.
- */
-static GLenum
-base_format(GLenum format)
-{
- switch (format) {
- case GL_DEPTH_COMPONENT:
- return GL_DEPTH_COMPONENT;
- case GL_DEPTH_STENCIL:
- return GL_DEPTH_STENCIL;
- case GL_STENCIL_INDEX:
- return GL_STENCIL_INDEX;
- default:
- return GL_RGBA;
- }
-}
-
-
/**
* Return a texture internalFormat for drawing/copying an image
* of the given format and type.
*/
static GLenum
-internal_format(GLenum format, GLenum type)
+internal_format(struct gl_context *ctx, GLenum format, GLenum type)
{
switch (format) {
case GL_DEPTH_COMPONENT:
- return GL_DEPTH_COMPONENT;
+ switch (type) {
+ case GL_UNSIGNED_SHORT:
+ return GL_DEPTH_COMPONENT16;
+
+ case GL_UNSIGNED_INT:
+ return GL_DEPTH_COMPONENT32;
+
+ case GL_FLOAT:
+ if (ctx->Extensions.ARB_depth_buffer_float)
+ return GL_DEPTH_COMPONENT32F;
+ else
+ return GL_DEPTH_COMPONENT;
+
+ default:
+ return GL_DEPTH_COMPONENT;
+ }
+
case GL_DEPTH_STENCIL:
- return GL_DEPTH_STENCIL;
+ switch (type) {
+ case GL_FLOAT_32_UNSIGNED_INT_24_8_REV:
+ return GL_DEPTH32F_STENCIL8;
+
+ case GL_UNSIGNED_INT_24_8:
+ default:
+ return GL_DEPTH24_STENCIL8;
+ }
+
case GL_STENCIL_INDEX:
return GL_STENCIL_INDEX;
+
default:
if (_mesa_is_integer_format(format)) {
switch (type) {
}
}
else {
- return GL_RGBA;
+ switch (type) {
+ case GL_UNSIGNED_BYTE:
+ case GL_UNSIGNED_INT_8_8_8_8:
+ case GL_UNSIGNED_INT_8_8_8_8_REV:
+ default:
+ return GL_RGBA8;
+
+ case GL_UNSIGNED_BYTE_3_3_2:
+ case GL_UNSIGNED_BYTE_2_3_3_REV:
+ case GL_UNSIGNED_SHORT_4_4_4_4:
+ case GL_UNSIGNED_SHORT_4_4_4_4_REV:
+ return GL_RGBA4;
+
+ case GL_UNSIGNED_SHORT_5_6_5:
+ case GL_UNSIGNED_SHORT_5_6_5_REV:
+ case GL_UNSIGNED_SHORT_5_5_5_1:
+ case GL_UNSIGNED_SHORT_1_5_5_5_REV:
+ return GL_RGB5_A1;
+
+ case GL_UNSIGNED_INT_10_10_10_2:
+ case GL_UNSIGNED_INT_2_10_10_10_REV:
+ return GL_RGB10_A2;
+
+ case GL_UNSIGNED_SHORT:
+ case GL_UNSIGNED_INT:
+ return GL_RGBA16;
+
+ case GL_BYTE:
+ return
+ ctx->Extensions.EXT_texture_snorm ? GL_RGBA8_SNORM : GL_RGBA8;
+
+ case GL_SHORT:
+ case GL_INT:
+ return
+ ctx->Extensions.EXT_texture_snorm ? GL_RGBA16_SNORM : GL_RGBA16;
+
+ case GL_HALF_FLOAT_ARB:
+ return
+ ctx->Extensions.ARB_texture_float ? GL_RGBA16F :
+ ctx->Extensions.EXT_texture_snorm ? GL_RGBA16_SNORM : GL_RGBA16;
+
+ case GL_FLOAT:
+ case GL_DOUBLE:
+ return
+ ctx->Extensions.ARB_texture_float ? GL_RGBA32F :
+ ctx->Extensions.EXT_texture_snorm ? GL_RGBA16_SNORM : GL_RGBA16;
+
+ case GL_UNSIGNED_INT_5_9_9_9_REV:
+ assert(ctx->Extensions.EXT_texture_shared_exponent);
+ return GL_RGB9_E5;
+
+ case GL_UNSIGNED_INT_10F_11F_11F_REV:
+ assert(ctx->Extensions.EXT_packed_float);
+ return GL_R11F_G11F_B10F;
+ }
}
}
}
gl_format mformat;
struct pipe_resource *pt;
enum pipe_format pipeFormat;
- GLuint cpp;
- GLenum baseFormat, intFormat;
+ GLenum baseInternalFormat, intFormat;
- baseFormat = base_format(format);
- intFormat = internal_format(format, type);
+ intFormat = internal_format(ctx, format, type);
+ baseInternalFormat = _mesa_base_tex_format(ctx, intFormat);
mformat = st_ChooseTextureFormat_renderable(ctx, intFormat,
format, type, GL_FALSE);
pipeFormat = st_mesa_format_to_pipe_format(mformat);
assert(pipeFormat);
- cpp = util_format_get_blocksize(pipeFormat);
pixels = _mesa_map_pbo_source(ctx, unpack, pixels);
if (!pixels)
* the texture. We deal with that with texcoords.
*/
success = _mesa_texstore(ctx, 2, /* dims */
- baseFormat, /* baseInternalFormat */
+ baseInternalFormat, /* baseInternalFormat */
mformat, /* gl_format */
dest, /* dest */
0, 0, 0, /* dstX/Y/Zoffset */
{
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);
else
usage = PIPE_TRANSFER_WRITE;
- pt = pipe_get_transfer(st_context(ctx)->pipe, strb->texture, 0, 0,
- usage, x, y,
- width, height);
+ 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);
for (row = 0; row < height; row++) {
GLubyte sValues[MAX_WIDTH];
GLuint zValues[MAX_WIDTH];
+ GLfloat *zValuesFloat = (GLfloat*)zValues;
GLenum destType = GL_UNSIGNED_BYTE;
const GLvoid *source = _mesa_image_address2d(&clippedUnpack, pixels,
width, height,
ctx->_ImageTransferState);
if (format == GL_DEPTH_STENCIL) {
- _mesa_unpack_depth_span(ctx, spanWidth, GL_UNSIGNED_INT, zValues,
+ GLenum ztype =
+ pt->resource->format == PIPE_FORMAT_Z32_FLOAT_S8X24_USCALED ?
+ GL_FLOAT : GL_UNSIGNED_INT;
+
+ _mesa_unpack_depth_span(ctx, spanWidth, ztype, zValues,
(1 << 24) - 1, type, source,
&clippedUnpack);
}
}
}
break;
+ case PIPE_FORMAT_Z32_FLOAT_S8X24_USCALED:
+ if (format == GL_DEPTH_STENCIL) {
+ uint *dest = (uint *) (stmap + spanY * pt->stride + spanX*4);
+ GLfloat *destf = (GLfloat*)dest;
+ GLint k;
+ assert(usage == PIPE_TRANSFER_WRITE);
+ for (k = 0; k < spanWidth; k++) {
+ destf[k*2] = zValuesFloat[k];
+ dest[k*2+1] = 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*2+1] = sValues[k] & 0xff;
+ }
+ }
+ break;
default:
assert(0);
}
GLboolean write_stencil = GL_FALSE, write_depth = GL_FALSE;
struct pipe_sampler_view *sv[2];
int num_sampler_view = 1;
- enum pipe_format stencil_format = PIPE_FORMAT_NONE;
struct st_fp_variant *fpv;
if (format == GL_DEPTH_STENCIL)
else if (format == GL_DEPTH_COMPONENT)
write_depth = GL_TRUE;
- if (write_stencil) {
- enum pipe_format tex_format;
- /* can we write to stencil if not fallback */
- if (!pipe->screen->get_param(pipe->screen, PIPE_CAP_SHADER_STENCIL_EXPORT))
- goto stencil_fallback;
-
- tex_format = st_choose_format(st->pipe->screen, base_format(format),
- PIPE_TEXTURE_2D,
- 0, PIPE_BIND_SAMPLER_VIEW);
- if (tex_format == PIPE_FORMAT_Z24_UNORM_S8_USCALED)
- stencil_format = PIPE_FORMAT_X24S8_USCALED;
- else if (tex_format == PIPE_FORMAT_S8_USCALED_Z24_UNORM)
- stencil_format = PIPE_FORMAT_S8X24_USCALED;
- else
- stencil_format = PIPE_FORMAT_S8_USCALED;
- if (stencil_format == PIPE_FORMAT_NONE)
- goto stencil_fallback;
+ if (write_stencil &&
+ !pipe->screen->get_param(pipe->screen, PIPE_CAP_SHADER_STENCIL_EXPORT)) {
+ /* software fallback */
+ draw_stencil_pixels(ctx, x, y, width, height, format, type,
+ unpack, pixels);
+ return;
}
/* Mesa state should be up to date by now */
sv[0] = st_create_texture_sampler_view(st->pipe, pt);
if (sv[0]) {
- if (write_stencil) {
+ /* Create a second sampler view to read stencil.
+ * The stencil is written using the shader stencil export
+ * functionality. */
+ if (write_stencil) {
+ enum pipe_format stencil_format = PIPE_FORMAT_NONE;
+
+ switch (pt->format) {
+ case PIPE_FORMAT_Z24_UNORM_S8_USCALED:
+ case PIPE_FORMAT_X24S8_USCALED:
+ stencil_format = PIPE_FORMAT_X24S8_USCALED;
+ break;
+ case PIPE_FORMAT_S8_USCALED_Z24_UNORM:
+ case PIPE_FORMAT_S8X24_USCALED:
+ stencil_format = PIPE_FORMAT_S8X24_USCALED;
+ break;
+ case PIPE_FORMAT_Z32_FLOAT_S8X24_USCALED:
+ case PIPE_FORMAT_X32_S8X24_USCALED:
+ stencil_format = PIPE_FORMAT_X32_S8X24_USCALED;
+ break;
+ case PIPE_FORMAT_S8_USCALED:
+ stencil_format = PIPE_FORMAT_S8_USCALED;
+ break;
+ default:
+ assert(0);
+ }
+
sv[1] = st_create_texture_sampler_view_format(st->pipe, pt,
stencil_format);
num_sampler_view++;
pipe_resource_reference(&pt, NULL);
}
}
- return;
-
-stencil_fallback:
- draw_stencil_pixels(ctx, x, y, width, height, format, type,
- unpack, pixels);
}
dsty = rbDraw->Base.Height - dsty - height;
}
- ptDraw = pipe_get_transfer(st_context(ctx)->pipe,
- rbDraw->texture, 0, 0,
+ ptDraw = pipe_get_transfer(pipe,
+ rbDraw->texture,
+ rbDraw->rtt_level,
+ rbDraw->rtt_face + rbDraw->rtt_slice,
usage, dstx, dsty,
width, height);
assert(usage == PIPE_TRANSFER_WRITE);
memcpy(dst, src, width);
break;
+ case PIPE_FORMAT_Z32_FLOAT_S8X24_USCALED:
+ {
+ uint *dst4 = (uint *) dst;
+ int j;
+ dst4++;
+ assert(usage == PIPE_TRANSFER_READ_WRITE);
+ for (j = 0; j < width; j++) {
+ *dst4 = src[j] & 0xff;
+ dst4 += 2;
+ }
+ }
+ break;
default:
assert(0);
}
}
+/** Do the src/dest regions overlap? */
+static GLboolean
+regions_overlap(GLint srcX, GLint srcY, GLint dstX, GLint dstY,
+ GLsizei width, GLsizei height)
+{
+ if (srcX + width <= dstX ||
+ dstX + width <= srcX ||
+ srcY + height <= dstY ||
+ dstY + height <= srcY)
+ return GL_FALSE;
+ else
+ return GL_TRUE;
+}
+
+
+/**
+ * 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;
+}
+
+
static void
st_CopyPixels(struct gl_context *ctx, GLint srcx, GLint srcy,
GLsizei width, GLsizei height,
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 (screen->is_format_supported(screen, srcFormat, st->internal_target,
sample_count,
- PIPE_BIND_SAMPLER_VIEW, 0)) {
+ 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,
- st->internal_target, sample_count,
- PIPE_BIND_DEPTH_STENCIL);
+ 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, st->internal_target,
+ 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);
}
if (srcFormat == texFormat) {
struct pipe_box src_box;
u_box_2d(readX, readY, readW, readH, &src_box);
- /* copy source framebuffer surface into mipmap/texture */
+ /* copy source framebuffer surface into mipmap/texture */
pipe->resource_copy_region(pipe,
pt, /* dest tex */
- 0,
+ 0, /* dest lvl */
pack.SkipPixels, pack.SkipRows, 0, /* dest pos */
rbRead->texture, /* src tex */
- 0,
+ rbRead->rtt_level, /* src lvl */
&src_box);
}
/* CPU-based fallback/conversion */
struct pipe_transfer *ptRead =
pipe_get_transfer(st->pipe, rbRead->texture,
- 0, 0, /* level, layer */
+ rbRead->rtt_level,
+ rbRead->rtt_face + rbRead->rtt_slice,
PIPE_TRANSFER_READ,
readX, readY, readW, readH);
struct pipe_transfer *ptTex;