mesa: consolidate texture-related code in meta.c

Also, allow using texture rectangles, NPOT textures or regular POT textures
(preferred in that order).
This commit is contained in:
Brian Paul 2009-08-30 09:15:24 -06:00
parent 7dd6fa12e1
commit 04f8193aad
1 changed files with 366 additions and 256 deletions

View File

@ -140,9 +140,6 @@ struct save_state
*/
struct blit_state
{
GLuint TexObj;
GLsizei TexWidth, TexHeight;
GLenum TexType;
GLuint ArrayObj;
GLuint VBO;
GLfloat verts[4][4]; /** four verts of X,Y,S,T */
@ -165,9 +162,6 @@ struct clear_state
*/
struct copypix_state
{
GLuint TexObj;
GLsizei TexWidth, TexHeight;
GLenum TexType;
GLuint ArrayObj;
GLuint VBO;
GLfloat verts[4][5]; /** four verts of X,Y,Z,S,T */
@ -179,15 +173,28 @@ struct copypix_state
*/
struct drawpix_state
{
GLuint TexObj;
GLsizei TexWidth, TexHeight;
GLenum TexIntFormat;
GLuint ArrayObj;
GLuint VBO;
GLfloat verts[4][5]; /** four verts of X,Y,Z,S,T */
};
/**
* Temporary texture used for glBlitFramebuffer, glDrawPixels, etc.
* This is currently shared by all the meta ops. But we could create a
* separate one for each of glDrawPixel, glBlitFramebuffer, glCopyPixels, etc.
*/
struct temp_texture
{
GLuint TexObj;
GLenum Target; /**< GL_TEXTURE_2D or GL_TEXTURE_RECTANGLE */
GLsizei MaxSize; /**< Max possible texture size */
GLboolean NPOT; /**< Non-power of two size OK? */
GLsizei Width, Height; /**< Current texture size */
GLenum IntFormat;
GLfloat Sright, Ttop; /**< right, top texcoords */
};
/**
* All per-context meta state.
@ -196,13 +203,14 @@ struct gl_meta_state
{
struct save_state Save; /**< state saved during meta-ops */
struct temp_texture TempTex;
struct blit_state Blit; /**< For _mesa_meta_blit_framebuffer() */
struct clear_state Clear; /**< For _mesa_meta_clear() */
struct copypix_state CopyPix; /**< For _mesa_meta_copy_pixels() */
struct drawpix_state DrawPix; /**< For _mesa_meta_draw_pixels() */
/* other possible meta-ops:
* glDrawPixels()
* glBitmap()
* glGenerateMipmap()
*/
@ -231,8 +239,11 @@ _mesa_meta_free(GLcontext *ctx)
{
struct gl_meta_state *meta = ctx->Meta;
if (meta->Blit.TexObj) {
_mesa_DeleteTextures(1, &meta->Blit.TexObj);
if (meta->TempTex.TexObj) {
_mesa_DeleteTextures(1, &meta->TempTex.TexObj);
}
if (meta->Blit.VBO) {
_mesa_DeleteBuffersARB(1, & meta->Blit.VBO);
_mesa_DeleteVertexArraysAPPLE(1, &meta->Blit.ArrayObj);
}
@ -242,14 +253,12 @@ _mesa_meta_free(GLcontext *ctx)
_mesa_DeleteVertexArraysAPPLE(1, &meta->Clear.ArrayObj);
}
if (meta->CopyPix.TexObj) {
_mesa_DeleteTextures(1, &meta->CopyPix.TexObj);
if (meta->CopyPix.VBO) {
_mesa_DeleteBuffersARB(1, & meta->CopyPix.VBO);
_mesa_DeleteVertexArraysAPPLE(1, &meta->CopyPix.ArrayObj);
}
if (meta->DrawPix.TexObj) {
_mesa_DeleteTextures(1, &meta->DrawPix.TexObj);
if (meta->DrawPix.VBO) {
_mesa_DeleteBuffersARB(1, & meta->DrawPix.VBO);
_mesa_DeleteVertexArraysAPPLE(1, &meta->DrawPix.ArrayObj);
}
@ -672,10 +681,182 @@ _mesa_meta_end(GLcontext *ctx)
}
/**
* Return pointer to temp_texture info. This does some one-time init
* if needed.
*/
static struct temp_texture *
get_temp_texture(GLcontext *ctx)
{
struct temp_texture *tex = &ctx->Meta->TempTex;
if (!tex->TexObj) {
/* do one-time init */
/* prefer texture rectangle */
if (0*ctx->Extensions.NV_texture_rectangle) {
tex->Target = GL_TEXTURE_RECTANGLE;
tex->MaxSize = ctx->Const.MaxTextureRectSize;
tex->NPOT = GL_TRUE;
}
else {
/* use 2D texture, NPOT if possible */
tex->Target = GL_TEXTURE_2D;
tex->MaxSize = 1 << (ctx->Const.MaxTextureLevels - 1);
tex->NPOT = 0*ctx->Extensions.ARB_texture_non_power_of_two;
}
assert(tex->MaxSize > 0);
_mesa_GenTextures(1, &tex->TexObj);
_mesa_BindTexture(tex->Target, tex->TexObj);
}
return tex;
}
/**
* Compute the width/height of texture needed to draw an image of the
* given size. Return a flag indicating whether the current texture
* can be re-used (glTexSubImage2D) or if a new texture needs to be
* allocated (glTexImage2D).
* Also, compute s/t texcoords for drawing.
*
* \return GL_TRUE if new texture is needed, GL_FALSE otherwise
*/
static GLboolean
alloc_texture(struct temp_texture *tex,
GLsizei width, GLsizei height, GLenum intFormat)
{
GLboolean newTex = GL_FALSE;
if (width > tex->Width ||
height > tex->Height ||
intFormat != tex->IntFormat) {
/* alloc new texture (larger or different format) */
if (tex->NPOT) {
/* use non-power of two size */
tex->Width = width;
tex->Height = height;
}
else {
/* find power of two size */
GLsizei w, h;
w = h = 16;
while (w < width)
w *= 2;
while (h < height)
h *= 2;
tex->Width = w;
tex->Height = h;
}
tex->IntFormat = intFormat;
newTex = GL_TRUE;
}
/* compute texcoords */
if (tex->Target == GL_TEXTURE_RECTANGLE) {
tex->Sright = (GLfloat) width;
tex->Ttop = (GLfloat) height;
}
else {
tex->Sright = (GLfloat) width / tex->Width;
tex->Ttop = (GLfloat) height / tex->Height;
}
return newTex;
}
/**
* Setup/load texture for glCopyPixels or glBlitFramebuffer.
*/
static void
setup_copypix_texture(struct temp_texture *tex,
GLboolean newTex,
GLint srcX, GLint srcY,
GLsizei width, GLsizei height, GLenum intFormat,
GLenum filter)
{
_mesa_BindTexture(tex->Target, tex->TexObj);
_mesa_TexParameteri(tex->Target, GL_TEXTURE_MIN_FILTER, filter);
_mesa_TexParameteri(tex->Target, GL_TEXTURE_MAG_FILTER, filter);
_mesa_TexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
/* copy framebuffer image to texture */
if (newTex) {
/* create new tex image */
if (tex->Width == width && tex->Height == height) {
/* create new tex with framebuffer data */
_mesa_CopyTexImage2D(tex->Target, 0, tex->IntFormat,
srcX, srcY, width, height, 0);
}
else {
/* create empty texture */
_mesa_TexImage2D(tex->Target, 0, tex->IntFormat,
tex->Width, tex->Height, 0,
intFormat, GL_UNSIGNED_BYTE, NULL);
/* load image */
_mesa_CopyTexSubImage2D(tex->Target, 0,
0, 0, srcX, srcY, width, height);
}
}
else {
/* replace existing tex image */
_mesa_CopyTexSubImage2D(tex->Target, 0,
0, 0, srcX, srcY, width, height);
}
}
/**
* Setup/load texture for glDrawPixels.
*/
static void
setup_drawpix_texture(struct temp_texture *tex,
GLboolean newTex,
GLenum texIntFormat,
GLsizei width, GLsizei height,
GLenum format, GLenum type,
const GLvoid *pixels)
{
_mesa_BindTexture(tex->Target, tex->TexObj);
_mesa_TexParameteri(tex->Target, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
_mesa_TexParameteri(tex->Target, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
_mesa_TexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
/* copy pixel data to texture */
if (newTex) {
/* create new tex image */
if (tex->Width == width && tex->Height == height) {
/* create new tex and load image data */
_mesa_TexImage2D(tex->Target, 0, tex->IntFormat,
tex->Width, tex->Height, 0, format, type, pixels);
}
else {
/* create empty texture */
_mesa_TexImage2D(tex->Target, 0, tex->IntFormat,
tex->Width, tex->Height, 0, format, type, NULL);
/* load image */
_mesa_TexSubImage2D(tex->Target, 0,
0, 0, width, height, format, type, pixels);
}
}
else {
/* replace existing tex image */
_mesa_TexSubImage2D(tex->Target, 0,
0, 0, width, height, format, type, pixels);
}
}
/**
* Meta implementation of ctx->Driver.BlitFramebuffer() in terms
* of texture mapping and polygon rendering.
* Note: this function requires GL_ARB_texture_rectangle support.
*/
void
_mesa_meta_blit_framebuffer(GLcontext *ctx,
@ -684,24 +865,23 @@ _mesa_meta_blit_framebuffer(GLcontext *ctx,
GLbitfield mask, GLenum filter)
{
struct blit_state *blit = &ctx->Meta->Blit;
struct temp_texture *tex = get_temp_texture(ctx);
const GLsizei maxTexSize = tex->MaxSize;
const GLint srcX = MIN2(srcX0, srcX1);
const GLint srcY = MIN2(srcY0, srcY1);
const GLint srcW = abs(srcX1 - srcX0);
const GLint srcH = abs(srcY1 - srcY0);
GLboolean srcFlipX = srcX1 < srcX0;
GLboolean srcFlipY = srcY1 < srcY0;
const GLboolean srcFlipX = srcX1 < srcX0;
const GLboolean srcFlipY = srcY1 < srcY0;
GLboolean newTex;
ASSERT(ctx->Extensions.NV_texture_rectangle);
if (srcW > ctx->Const.MaxTextureRectSize ||
srcH > ctx->Const.MaxTextureRectSize) {
if (srcW > maxTexSize || srcH > maxTexSize) {
/* XXX avoid this fallback */
_swrast_BlitFramebuffer(ctx, srcX0, srcY0, srcX1, srcY1,
dstX0, dstY0, dstX1, dstY1, mask, filter);
return;
}
if (srcFlipX) {
GLint tmp = dstX0;
dstX0 = dstX1;
@ -717,21 +897,6 @@ _mesa_meta_blit_framebuffer(GLcontext *ctx,
/* only scissor effects blit so save/clear all other relevant state */
_mesa_meta_begin(ctx, ~META_SCISSOR);
if (blit->TexObj == 0) {
/* one-time setup */
/* create texture object */
_mesa_GenTextures(1, &blit->TexObj);
_mesa_BindTexture(GL_TEXTURE_RECTANGLE, blit->TexObj);
_mesa_TexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
}
else {
_mesa_BindTexture(GL_TEXTURE_RECTANGLE, blit->TexObj);
}
_mesa_TexParameteri(GL_TEXTURE_RECTANGLE, GL_TEXTURE_MIN_FILTER, filter);
_mesa_TexParameteri(GL_TEXTURE_RECTANGLE, GL_TEXTURE_MAG_FILTER, filter);
if (blit->ArrayObj == 0) {
/* one-time setup */
@ -758,57 +923,49 @@ _mesa_meta_blit_framebuffer(GLcontext *ctx,
_mesa_BindBufferARB(GL_ARRAY_BUFFER_ARB, blit->VBO);
}
/* vertex positions */
blit->verts[0][0] = (GLfloat) dstX0;
blit->verts[0][1] = (GLfloat) dstY0;
blit->verts[1][0] = (GLfloat) dstX1;
blit->verts[1][1] = (GLfloat) dstY0;
blit->verts[2][0] = (GLfloat) dstX1;
blit->verts[2][1] = (GLfloat) dstY1;
blit->verts[3][0] = (GLfloat) dstX0;
blit->verts[3][1] = (GLfloat) dstY1;
newTex = alloc_texture(tex, srcW, srcH, GL_RGBA);
/* texcoords */
blit->verts[0][2] = 0.0F;
blit->verts[0][3] = 0.0F;
blit->verts[1][2] = (GLfloat) srcW;
blit->verts[1][3] = 0.0F;
blit->verts[2][2] = (GLfloat) srcW;
blit->verts[2][3] = (GLfloat) srcH;
blit->verts[3][2] = 0.0F;
blit->verts[3][3] = (GLfloat) srcH;
/* vertex positions/texcoords (after texture allocation!) */
{
blit->verts[0][0] = (GLfloat) dstX0;
blit->verts[0][1] = (GLfloat) dstY0;
blit->verts[1][0] = (GLfloat) dstX1;
blit->verts[1][1] = (GLfloat) dstY0;
blit->verts[2][0] = (GLfloat) dstX1;
blit->verts[2][1] = (GLfloat) dstY1;
blit->verts[3][0] = (GLfloat) dstX0;
blit->verts[3][1] = (GLfloat) dstY1;
/* upload new vertex data */
_mesa_BufferSubDataARB(GL_ARRAY_BUFFER_ARB, 0,
sizeof(blit->verts), blit->verts);
blit->verts[0][2] = 0.0F;
blit->verts[0][3] = 0.0F;
blit->verts[1][2] = tex->Sright;
blit->verts[1][3] = 0.0F;
blit->verts[2][2] = tex->Sright;
blit->verts[2][3] = tex->Ttop;
blit->verts[3][2] = 0.0F;
blit->verts[3][3] = tex->Ttop;
/* copy framebuffer image to texture */
if (mask & GL_COLOR_BUFFER_BIT) {
if (blit->TexWidth == srcW &&
blit->TexHeight == srcH &&
blit->TexType == GL_RGBA) {
/* replace existing tex image */
_mesa_CopyTexSubImage2D(GL_TEXTURE_RECTANGLE, 0,
0, 0, srcX, srcY, srcW, srcH);
}
else {
/* create new tex image */
_mesa_CopyTexImage2D(GL_TEXTURE_RECTANGLE, 0, GL_RGBA,
srcX, srcY, srcW, srcH, 0);
blit->TexWidth = srcW;
blit->TexHeight = srcH;
blit->TexType = GL_RGBA;
}
mask &= ~GL_COLOR_BUFFER_BIT;
/* upload new vertex data */
_mesa_BufferSubDataARB(GL_ARRAY_BUFFER_ARB, 0,
sizeof(blit->verts), blit->verts);
}
_mesa_Enable(GL_TEXTURE_RECTANGLE);
_mesa_Enable(tex->Target);
/* draw textured quad */
_mesa_DrawArrays(GL_TRIANGLE_FAN, 0, 4);
if (mask & GL_COLOR_BUFFER_BIT) {
setup_copypix_texture(tex, newTex, srcX, srcY, srcW, srcH,
GL_RGBA, filter);
_mesa_DrawArrays(GL_TRIANGLE_FAN, 0, 4);
mask &= ~GL_COLOR_BUFFER_BIT;
}
if (mask & GL_DEPTH_BUFFER_BIT) {
/* XXX todo (need fragment shader) */
}
if (mask & GL_STENCIL_BUFFER_BIT) {
/* XXX can't easily do stencil */
}
_mesa_Disable(GL_TEXTURE_RECTANGLE);
_mesa_Disable(tex->Target);
_mesa_meta_end(ctx);
@ -827,8 +984,6 @@ void
_mesa_meta_clear(GLcontext *ctx, GLbitfield buffers)
{
struct clear_state *clear = &ctx->Meta->Clear;
GLfloat z = 1.0 - 2.0 * ctx->Depth.Clear;
GLuint i;
/* only scissor and color mask effects clearing */
_mesa_meta_begin(ctx, ~(META_SCISSOR | META_COLOR_MASK));
@ -889,29 +1044,38 @@ _mesa_meta_clear(GLcontext *ctx, GLbitfield buffers)
assert(!ctx->Stencil.Enabled);
}
/* vertex positions */
clear->verts[0][0] = (GLfloat) ctx->DrawBuffer->_Xmin;
clear->verts[0][1] = (GLfloat) ctx->DrawBuffer->_Ymin;
clear->verts[0][2] = z;
clear->verts[1][0] = (GLfloat) ctx->DrawBuffer->_Xmax;
clear->verts[1][1] = (GLfloat) ctx->DrawBuffer->_Ymin;
clear->verts[1][2] = z;
clear->verts[2][0] = (GLfloat) ctx->DrawBuffer->_Xmax;
clear->verts[2][1] = (GLfloat) ctx->DrawBuffer->_Ymax;
clear->verts[2][2] = z;
clear->verts[3][0] = (GLfloat) ctx->DrawBuffer->_Xmin;
clear->verts[3][1] = (GLfloat) ctx->DrawBuffer->_Ymax;
clear->verts[3][2] = z;
/* vertex positions/colors */
{
const GLfloat x0 = (GLfloat) ctx->DrawBuffer->_Xmin;
const GLfloat y0 = (GLfloat) ctx->DrawBuffer->_Ymin;
const GLfloat x1 = (GLfloat) ctx->DrawBuffer->_Xmax;
const GLfloat y1 = (GLfloat) ctx->DrawBuffer->_Ymax;
const GLfloat z = 1.0 - 2.0 * ctx->Depth.Clear;
GLuint i;
/* vertex colors */
for (i = 0; i < 4; i++) {
COPY_4FV(&clear->verts[i][3], ctx->Color.ClearColor);
clear->verts[0][0] = x0;
clear->verts[0][1] = y0;
clear->verts[0][2] = z;
clear->verts[1][0] = x1;
clear->verts[1][1] = y0;
clear->verts[1][2] = z;
clear->verts[2][0] = x1;
clear->verts[2][1] = y1;
clear->verts[2][2] = z;
clear->verts[3][0] = x0;
clear->verts[3][1] = y1;
clear->verts[3][2] = z;
/* vertex colors */
for (i = 0; i < 4; i++) {
COPY_4FV(&clear->verts[i][3], ctx->Color.ClearColor);
}
/* upload new vertex data */
_mesa_BufferSubDataARB(GL_ARRAY_BUFFER_ARB, 0,
sizeof(clear->verts), clear->verts);
}
/* upload new vertex data */
_mesa_BufferSubDataARB(GL_ARRAY_BUFFER_ARB, 0,
sizeof(clear->verts), clear->verts);
/* draw quad */
_mesa_DrawArrays(GL_TRIANGLE_FAN, 0, 4);
@ -922,26 +1086,22 @@ _mesa_meta_clear(GLcontext *ctx, GLbitfield buffers)
/**
* Meta implementation of ctx->Driver.CopyPixels() in terms
* of texture mapping and polygon rendering.
* Note: this function requires GL_ARB_texture_rectangle support.
*/
void
_mesa_meta_copy_pixels(GLcontext *ctx, GLint srcX, GLint srcY,
GLsizei width, GLsizei height,
GLint dstX, GLint dstY, GLenum type)
{
const GLenum filter = GL_NEAREST;
struct copypix_state *copypix = &ctx->Meta->CopyPix;
const GLfloat z = ctx->Current.RasterPos[2];
const GLfloat dstX1 = dstX + width * ctx->Pixel.ZoomX;
const GLfloat dstY1 = dstY + height * ctx->Pixel.ZoomY;
ASSERT(ctx->Extensions.NV_texture_rectangle);
struct temp_texture *tex = get_temp_texture(ctx);
GLboolean newTex;
GLenum intFormat = GL_RGBA;
if (type != GL_COLOR ||
ctx->_ImageTransferState ||
ctx->Fog.Enabled ||
width > ctx->Const.MaxTextureRectSize ||
height > ctx->Const.MaxTextureRectSize) {
width > tex->MaxSize ||
height > tex->MaxSize) {
/* XXX avoid this fallback */
_swrast_CopyPixels(ctx, srcX, srcY, width, height, dstX, dstY, type);
return;
@ -957,20 +1117,6 @@ _mesa_meta_copy_pixels(GLcontext *ctx, GLint srcX, GLint srcY,
META_VERTEX |
META_VIEWPORT));
if (copypix->TexObj == 0) {
/* one-time setup */
/* create texture object */
_mesa_GenTextures(1, &copypix->TexObj);
_mesa_BindTexture(GL_TEXTURE_RECTANGLE, copypix->TexObj);
_mesa_TexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
_mesa_TexParameteri(GL_TEXTURE_RECTANGLE, GL_TEXTURE_MIN_FILTER, filter);
_mesa_TexParameteri(GL_TEXTURE_RECTANGLE, GL_TEXTURE_MAG_FILTER, filter);
}
else {
_mesa_BindTexture(GL_TEXTURE_RECTANGLE, copypix->TexObj);
}
if (copypix->ArrayObj == 0) {
/* one-time setup */
@ -997,66 +1143,52 @@ _mesa_meta_copy_pixels(GLcontext *ctx, GLint srcX, GLint srcY,
_mesa_BindBufferARB(GL_ARRAY_BUFFER_ARB, copypix->VBO);
}
/* vertex positions, texcoords */
copypix->verts[0][0] = (GLfloat) dstX;
copypix->verts[0][1] = (GLfloat) dstY;
copypix->verts[0][2] = z;
copypix->verts[0][3] = 0.0F;
copypix->verts[0][4] = 0.0F;
copypix->verts[1][0] = (GLfloat) dstX1;
copypix->verts[1][1] = (GLfloat) dstY;
copypix->verts[1][2] = z;
copypix->verts[1][3] = (GLfloat) width;
copypix->verts[1][4] = 0.0F;
copypix->verts[2][0] = (GLfloat) dstX1;
copypix->verts[2][1] = (GLfloat) dstY1;
copypix->verts[2][2] = z;
copypix->verts[2][3] = (GLfloat) width;
copypix->verts[2][4] = (GLfloat) height;
copypix->verts[3][0] = (GLfloat) dstX;
copypix->verts[3][1] = (GLfloat) dstY1;
copypix->verts[3][2] = z;
copypix->verts[3][3] = 0.0F;
copypix->verts[3][4] = (GLfloat) height;
newTex = alloc_texture(tex, width, height, intFormat);
/* upload new vertex data */
_mesa_BufferSubDataARB(GL_ARRAY_BUFFER_ARB, 0,
sizeof(copypix->verts), copypix->verts);
/* vertex positions, texcoords (after texture allocation!) */
{
const GLfloat dstX0 = (GLfloat) dstX;
const GLfloat dstY0 = (GLfloat) dstY;
const GLfloat dstX1 = dstX + width * ctx->Pixel.ZoomX;
const GLfloat dstY1 = dstY + height * ctx->Pixel.ZoomY;
const GLfloat z = ctx->Current.RasterPos[2];
/* copy framebuffer image to texture */
if (type == GL_COLOR) {
if (copypix->TexWidth == width &&
copypix->TexHeight == height &&
copypix->TexType == type) {
/* replace existing tex image */
_mesa_CopyTexSubImage2D(GL_TEXTURE_RECTANGLE, 0,
0, 0, srcX, srcY, width, height);
}
else {
/* create new tex image */
_mesa_CopyTexImage2D(GL_TEXTURE_RECTANGLE, 0, GL_RGBA,
srcX, srcY, width, height, 0);
copypix->TexWidth = width;
copypix->TexHeight = height;
copypix->TexType = type;
}
}
else if (type == GL_DEPTH) {
/* TO-DO: Use a GL_DEPTH_COMPONENT texture and a fragment program/shader
* that replaces the fragment.z value.
*/
}
else {
ASSERT(type == GL_STENCIL);
/* have to use sw fallback */
copypix->verts[0][0] = dstX0;
copypix->verts[0][1] = dstY0;
copypix->verts[0][2] = z;
copypix->verts[0][3] = 0.0F;
copypix->verts[0][4] = 0.0F;
copypix->verts[1][0] = dstX1;
copypix->verts[1][1] = dstY0;
copypix->verts[1][2] = z;
copypix->verts[1][3] = tex->Sright;
copypix->verts[1][4] = 0.0F;
copypix->verts[2][0] = dstX1;
copypix->verts[2][1] = dstY1;
copypix->verts[2][2] = z;
copypix->verts[2][3] = tex->Sright;
copypix->verts[2][4] = tex->Ttop;
copypix->verts[3][0] = dstX0;
copypix->verts[3][1] = dstY1;
copypix->verts[3][2] = z;
copypix->verts[3][3] = 0.0F;
copypix->verts[3][4] = tex->Ttop;
/* upload new vertex data */
_mesa_BufferSubDataARB(GL_ARRAY_BUFFER_ARB, 0,
sizeof(copypix->verts), copypix->verts);
}
_mesa_Enable(GL_TEXTURE_RECTANGLE);
/* Alloc/setup texture */
setup_copypix_texture(tex, newTex, srcX, srcY, width, height,
GL_RGBA, GL_NEAREST);
_mesa_Enable(tex->Target);
/* draw textured quad */
_mesa_DrawArrays(GL_TRIANGLE_FAN, 0, 4);
_mesa_Disable(GL_TEXTURE_RECTANGLE);
_mesa_Disable(tex->Target);
_mesa_meta_end(ctx);
}
@ -1070,23 +1202,26 @@ _mesa_meta_copy_pixels(GLcontext *ctx, GLint srcX, GLint srcY,
*/
static void
tiled_draw_pixels(GLcontext *ctx,
GLint tileSize,
GLint x, GLint y, GLsizei width, GLsizei height,
GLenum format, GLenum type,
const struct gl_pixelstore_attrib *unpack,
const GLvoid *pixels)
{
const GLint maxSize = ctx->Const.MaxTextureRectSize;
struct gl_pixelstore_attrib tileUnpack = *unpack;
GLint i, j;
for (i = 0; i < width; i += maxSize) {
const GLint tileWidth = MIN2(maxSize, width - i);
if (tileUnpack.RowLength == 0)
tileUnpack.RowLength = width;
for (i = 0; i < width; i += tileSize) {
const GLint tileWidth = MIN2(tileSize, width - i);
const GLint tileX = (GLint) (x + i * ctx->Pixel.ZoomX);
tileUnpack.SkipPixels = unpack->SkipPixels + i;
for (j = 0; j < height; j += maxSize) {
const GLint tileHeight = MIN2(maxSize, height - j);
for (j = 0; j < height; j += tileSize) {
const GLint tileHeight = MIN2(tileSize, height - j);
const GLint tileY = (GLint) (y + j * ctx->Pixel.ZoomY);
tileUnpack.SkipRows = unpack->SkipRows + j;
@ -1102,7 +1237,6 @@ tiled_draw_pixels(GLcontext *ctx,
/**
* Meta implementation of ctx->Driver.DrawPixels() in terms
* of texture mapping and polygon rendering.
* Note: this function requires GL_ARB_texture_rectangle support.
*/
void
_mesa_meta_draw_pixels(GLcontext *ctx,
@ -1111,16 +1245,11 @@ _mesa_meta_draw_pixels(GLcontext *ctx,
const struct gl_pixelstore_attrib *unpack,
const GLvoid *pixels)
{
const GLenum filter = GL_NEAREST;
struct drawpix_state *drawpix = &ctx->Meta->DrawPix;
const GLfloat z = ctx->Current.RasterPos[2];
const GLfloat x1 = x + width * ctx->Pixel.ZoomX;
const GLfloat y1 = y + height * ctx->Pixel.ZoomY;
struct temp_texture *tex = get_temp_texture(ctx);
const struct gl_pixelstore_attrib unpackSave = ctx->Unpack;
GLenum texIntFormat;
GLboolean fallback;
ASSERT(ctx->Extensions.NV_texture_rectangle);
GLboolean fallback, newTex;
/*
* Determine if we can do the glDrawPixels with texture mapping.
@ -1147,15 +1276,14 @@ _mesa_meta_draw_pixels(GLcontext *ctx,
/*
* Check image size against max texture size, draw as tiles if needed.
*/
if (width > ctx->Const.MaxTextureRectSize ||
height > ctx->Const.MaxTextureRectSize) {
tiled_draw_pixels(ctx, x, y, width, height,
if (width > tex->MaxSize || height > tex->MaxSize) {
tiled_draw_pixels(ctx, tex->MaxSize, x, y, width, height,
format, type, unpack, pixels);
return;
}
/* Most GL state applies to glDrawPixels, but a there's a few things
* we need to override:
/* Most GL state applies to glDrawPixels (like blending, stencil, etc),
* but a there's a few things we need to override:
*/
_mesa_meta_begin(ctx, (META_RASTERIZATION |
META_SHADER |
@ -1164,20 +1292,6 @@ _mesa_meta_draw_pixels(GLcontext *ctx,
META_VERTEX |
META_VIEWPORT));
if (drawpix->TexObj == 0) {
/* one-time setup */
/* create texture object */
_mesa_GenTextures(1, &drawpix->TexObj);
_mesa_BindTexture(GL_TEXTURE_RECTANGLE, drawpix->TexObj);
_mesa_TexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
_mesa_TexParameteri(GL_TEXTURE_RECTANGLE, GL_TEXTURE_MIN_FILTER, filter);
_mesa_TexParameteri(GL_TEXTURE_RECTANGLE, GL_TEXTURE_MAG_FILTER, filter);
}
else {
_mesa_BindTexture(GL_TEXTURE_RECTANGLE, drawpix->TexObj);
}
if (drawpix->ArrayObj == 0) {
/* one-time setup */
@ -1204,61 +1318,57 @@ _mesa_meta_draw_pixels(GLcontext *ctx,
_mesa_BindBufferARB(GL_ARRAY_BUFFER_ARB, drawpix->VBO);
}
/* vertex positions, texcoords */
drawpix->verts[0][0] = (GLfloat) x;
drawpix->verts[0][1] = (GLfloat) y;
drawpix->verts[0][2] = z;
drawpix->verts[0][3] = 0.0F;
drawpix->verts[0][4] = 0.0F;
drawpix->verts[1][0] = (GLfloat) x1;
drawpix->verts[1][1] = (GLfloat) y;
drawpix->verts[1][2] = z;
drawpix->verts[1][3] = (GLfloat) width;
drawpix->verts[1][4] = 0.0F;
drawpix->verts[2][0] = (GLfloat) x1;
drawpix->verts[2][1] = (GLfloat) y1;
drawpix->verts[2][2] = z;
drawpix->verts[2][3] = (GLfloat) width;
drawpix->verts[2][4] = (GLfloat) height;
drawpix->verts[3][0] = (GLfloat) x;
drawpix->verts[3][1] = (GLfloat) y1;
drawpix->verts[3][2] = z;
drawpix->verts[3][3] = 0.0F;
drawpix->verts[3][4] = (GLfloat) height;
newTex = alloc_texture(tex, width, height, texIntFormat);
/* upload new vertex data */
_mesa_BufferSubDataARB(GL_ARRAY_BUFFER_ARB, 0,
sizeof(drawpix->verts), drawpix->verts);
/* vertex positions, texcoords (after texture allocation!) */
{
const GLfloat x0 = (GLfloat) x;
const GLfloat y0 = (GLfloat) y;
const GLfloat x1 = x + width * ctx->Pixel.ZoomX;
const GLfloat y1 = y + height * ctx->Pixel.ZoomY;
const GLfloat z = ctx->Current.RasterPos[2];
drawpix->verts[0][0] = x0;
drawpix->verts[0][1] = y0;
drawpix->verts[0][2] = z;
drawpix->verts[0][3] = 0.0F;
drawpix->verts[0][4] = 0.0F;
drawpix->verts[1][0] = x1;
drawpix->verts[1][1] = y0;
drawpix->verts[1][2] = z;
drawpix->verts[1][3] = tex->Sright;
drawpix->verts[1][4] = 0.0F;
drawpix->verts[2][0] = x1;
drawpix->verts[2][1] = y1;
drawpix->verts[2][2] = z;
drawpix->verts[2][3] = tex->Sright;
drawpix->verts[2][4] = tex->Ttop;
drawpix->verts[3][0] = x0;
drawpix->verts[3][1] = y1;
drawpix->verts[3][2] = z;
drawpix->verts[3][3] = 0.0F;
drawpix->verts[3][4] = tex->Ttop;
/* upload new vertex data */
_mesa_BufferSubDataARB(GL_ARRAY_BUFFER_ARB, 0,
sizeof(drawpix->verts), drawpix->verts);
}
/* set given unpack params */
ctx->Unpack = *unpack; /* XXX bufobj */
ctx->Unpack = *unpack;
/* copy pixel data to texture */
if (drawpix->TexWidth == width &&
drawpix->TexHeight == height &&
drawpix->TexIntFormat == texIntFormat) {
/* replace existing tex image */
_mesa_TexSubImage2D(GL_TEXTURE_RECTANGLE, 0,
0, 0, width, height, format, type, pixels);
}
else {
/* create new tex image */
_mesa_TexImage2D(GL_TEXTURE_RECTANGLE, 0, texIntFormat,
width, height, 0, format, type, pixels);
drawpix->TexWidth = width;
drawpix->TexHeight = height;
drawpix->TexIntFormat = texIntFormat;
}
setup_drawpix_texture(tex, newTex, texIntFormat, width, height,
format, type, pixels);
/* restore unpack params */
ctx->Unpack = unpackSave; /* XXX bufobj */
ctx->Unpack = unpackSave;
_mesa_Enable(GL_TEXTURE_RECTANGLE);
_mesa_Enable(tex->Target);
/* draw textured quad */
_mesa_DrawArrays(GL_TRIANGLE_FAN, 0, 4);
_mesa_Disable(GL_TEXTURE_RECTANGLE);
_mesa_Disable(tex->Target);
_mesa_meta_end(ctx);
}