#include "main/convolve.h"
#endif
#include "main/enums.h"
+#include "main/formats.h"
#include "main/image.h"
#include "main/imports.h"
#include "main/macros.h"
#include "main/mipmap.h"
#include "main/pixel.h"
#include "main/texcompress.h"
+#include "main/texfetch.h"
#include "main/texformat.h"
#include "main/texgetimage.h"
#include "main/teximage.h"
#include "main/texobj.h"
#include "main/texstore.h"
+#include "state_tracker/st_debug.h"
#include "state_tracker/st_context.h"
#include "state_tracker/st_cb_fbo.h"
#include "state_tracker/st_cb_texture.h"
#include "pipe/p_context.h"
#include "pipe/p_defines.h"
#include "pipe/p_inlines.h"
+#include "pipe/p_shader_tokens.h"
#include "util/u_tile.h"
#include "util/u_blit.h"
#include "util/u_surface.h"
* format.
*/
static GLuint
-compressed_num_bytes(GLuint mesaFormat)
+compressed_num_bytes(gl_format format)
{
- switch(mesaFormat) {
+ switch (format) {
#if FEATURE_texture_fxt1
case MESA_FORMAT_RGB_FXT1:
case MESA_FORMAT_RGBA_FXT1:
static GLboolean
-is_compressed_mesa_format(const struct gl_texture_format *format)
+is_compressed_mesa_format(gl_format format)
{
- switch (format->MesaFormat) {
+ switch (format) {
case MESA_FORMAT_RGB_DXT1:
case MESA_FORMAT_RGBA_DXT1:
case MESA_FORMAT_RGBA_DXT3:
stObj->base.MinFilter == GL_LINEAR ||
stImage->base._BaseFormat == GL_DEPTH_COMPONENT ||
stImage->base._BaseFormat == GL_DEPTH_STENCIL_EXT) &&
+ !stObj->base.GenerateMipmap &&
stImage->level == firstLevel) {
+ /* only alloc space for a single mipmap level */
lastLevel = firstLevel;
}
else {
+ /* alloc space for a full mipmap */
GLuint l2width = util_logbase2(width);
GLuint l2height = util_logbase2(height);
GLuint l2depth = util_logbase2(depth);
lastLevel = firstLevel + MAX2(MAX2(l2width, l2height), l2depth);
}
- fmt = st_mesa_format_to_pipe_format(stImage->base.TexFormat->MesaFormat);
+ fmt = st_mesa_format_to_pipe_format(stImage->base.TexFormat);
usage = default_usage(fmt);
const GLuint dstImageOffsets[1] = {0};
struct st_texture_image *stImage = st_texture_image(texImage);
struct pipe_screen *screen = ctx->st->pipe->screen;
- const struct gl_texture_format *mesa_format;
+ gl_format mesa_format;
struct pipe_texture templ;
struct pipe_texture *src_tex;
struct pipe_surface *dst_surface;
struct pipe_transfer *tex_xfer;
void *map;
-
if (!stImage->pt) {
/* XXX: Can this happen? Should we assert? */
return GL_FALSE;
*/
memset(&templ, 0, sizeof(templ));
templ.target = PIPE_TEXTURE_2D;
- templ.format = st_mesa_format_to_pipe_format(mesa_format->MesaFormat);
+ templ.format = st_mesa_format_to_pipe_format(mesa_format);
pf_get_block(templ.format, &templ.block);
templ.width[0] = width;
templ.height[0] = height;
0, 0, width, height); /* x, y, w, h */
map = screen->transfer_map(screen, tex_xfer);
- mesa_format->StoreImage(ctx, 2, GL_RGBA, mesa_format,
- map, /* dest ptr */
- 0, 0, 0, /* dest x/y/z offset */
- tex_xfer->stride, /* dest row stride (bytes) */
- dstImageOffsets, /* image offsets (for 3D only) */
- width, height, 1, /* size */
- format, type, /* source format/type */
- pixels, /* source data */
- unpack); /* source data packing */
+ _mesa_texstore(ctx, 2, GL_RGBA, mesa_format,
+ map, /* dest ptr */
+ 0, 0, 0, /* dest x/y/z offset */
+ tex_xfer->stride, /* dest row stride (bytes) */
+ dstImageOffsets, /* image offsets (for 3D only) */
+ width, height, 1, /* size */
+ format, type, /* source format/type */
+ pixels, /* source data */
+ unpack); /* source data packing */
screen->transfer_unmap(screen, tex_xfer);
screen->tex_transfer_destroy(tex_xfer);
struct st_texture_image *stImage = st_texture_image(texImage);
GLint postConvWidth, postConvHeight;
GLint texelBytes, sizeInBytes;
- GLuint dstRowStride;
+ GLuint dstRowStride = 0;
struct gl_pixelstore_attrib unpackNB;
- enum pipe_transfer_usage transfer_usage;
+ enum pipe_transfer_usage transfer_usage = 0;
DBG("%s target %s level %d %dx%dx%d border %d\n", __FUNCTION__,
_mesa_lookup_enum_by_nr(target), level, width, height, depth, border);
+ /* switch to "normal" */
+ if (stObj->surface_based) {
+ _mesa_clear_texture_object(ctx, texObj);
+ stObj->surface_based = GL_FALSE;
+ }
+
/* gallium does not support texture borders, strip it off */
if (border) {
strip_texture_border(border, &width, &height, &depth, unpack, &unpackNB);
}
#endif
- /* choose the texture format */
- texImage->TexFormat = st_ChooseTextureFormat(ctx, internalFormat,
- format, type);
-
_mesa_set_fetch_functions(texImage, dims);
- if (texImage->TexFormat->TexelBytes == 0) {
+ if (_mesa_is_format_compressed(texImage->TexFormat)) {
/* must be a compressed format */
texelBytes = 0;
- texImage->IsCompressed = GL_TRUE;
- texImage->CompressedSize =
- ctx->Driver.CompressedTextureSize(ctx, texImage->Width,
- texImage->Height, texImage->Depth,
- texImage->TexFormat->MesaFormat);
}
else {
- texelBytes = texImage->TexFormat->TexelBytes;
+ texelBytes = _mesa_get_format_bytes(texImage->TexFormat);
/* Minimum pitch of 32 bytes */
if (postConvWidth * texelBytes < 32) {
format, type,
pixels, unpack, "glTexImage");
}
- if (!pixels)
- return;
+
+ /* Note: we can't check for pixels==NULL until after we've allocated
+ * memory for the texture.
+ */
/* See if we can do texture compression with a blit/render.
*/
stImage->pt->format,
stImage->pt->target,
PIPE_TEXTURE_USAGE_RENDER_TARGET, 0)) {
+ if (!pixels)
+ goto done;
+
if (compress_with_blit(ctx, target, level, 0, 0, 0, width, height, depth,
format, type, pixels, unpack, texImage)) {
goto done;
}
else {
/* Allocate regular memory and store the image there temporarily. */
- if (texImage->IsCompressed) {
- sizeInBytes = texImage->CompressedSize;
- dstRowStride =
- _mesa_compressed_row_stride(texImage->TexFormat->MesaFormat, width);
+ if (_mesa_is_format_compressed(texImage->TexFormat)) {
+ sizeInBytes = _mesa_format_image_size(texImage->TexFormat,
+ texImage->Width,
+ texImage->Height,
+ texImage->Depth);
+ dstRowStride = _mesa_format_row_stride(texImage->TexFormat, width);
assert(dims != 3);
}
else {
return;
}
+ if (!pixels)
+ goto done;
+
DBG("Upload image %dx%dx%d row_len %x pitch %x\n",
width, height, depth, width * texelBytes, dstRowStride);
const GLubyte *src = (const GLubyte *) pixels;
for (i = 0; i < depth; i++) {
- if (!texImage->TexFormat->StoreImage(ctx, dims,
- texImage->_BaseFormat,
- texImage->TexFormat,
- texImage->Data,
- 0, 0, 0, /* dstX/Y/Zoffset */
- dstRowStride,
- texImage->ImageOffsets,
- width, height, 1,
- format, type, src, unpack)) {
+ if (!_mesa_texstore(ctx, dims,
+ texImage->_BaseFormat,
+ texImage->TexFormat,
+ texImage->Data,
+ 0, 0, 0, /* dstX/Y/Zoffset */
+ dstRowStride,
+ texImage->ImageOffsets,
+ width, height, 1,
+ format, type, src, unpack)) {
_mesa_error(ctx, GL_OUT_OF_MEMORY, "glTexImage");
}
}
}
+done:
_mesa_unmap_teximage_pbo(ctx, unpack);
-done:
if (stImage->pt && texImage->Data) {
st_texture_image_unmap(ctx->st, stImage);
texImage->Data = NULL;
}
-
- if (level == texObj->BaseLevel && texObj->GenerateMipmap) {
- ctx->Driver.GenerateMipmap(ctx, target, texObj);
- }
}
PIPE_TRANSFER_READ,
0, 0, width, height);
- pixels = _mesa_map_readpix_pbo(ctx, &ctx->Pack, pixels);
+ pixels = _mesa_map_pbo_dest(ctx, &ctx->Pack, pixels);
/* copy/pack data into user buffer */
if (st_equal_formats(stImage->pt->format, format, type)) {
GLvoid *dest = _mesa_image_address2d(&ctx->Pack, pixels, width,
height, format, type, row, 0);
+ if (ST_DEBUG & DEBUG_FALLBACK)
+ debug_printf("%s: fallback format translation\n", __FUNCTION__);
+
/* get float[4] rgba row from surface */
pipe_get_tile_rgba(tex_xfer, 0, row, width, 1, rgba);
}
}
- _mesa_unmap_readpix_pbo(ctx, &ctx->Pack);
+ _mesa_unmap_pbo_dest(ctx, &ctx->Pack);
/* destroy the temp / dest surface */
util_destroy_rgba_surface(dst_texture, dst_surface);
if (!texImage->Data) {
_mesa_error(ctx, GL_OUT_OF_MEMORY, "glTexSubImage");
- return;
+ goto done;
}
src = (const GLubyte *) pixels;
dstRowStride = stImage->transfer->stride;
for (i = 0; i < depth; i++) {
- if (!texImage->TexFormat->StoreImage(ctx, dims, texImage->_BaseFormat,
- texImage->TexFormat,
- texImage->Data,
- 0, 0, 0,
- dstRowStride,
- texImage->ImageOffsets,
- width, height, 1,
- format, type, src, packing)) {
+ if (!_mesa_texstore(ctx, dims, texImage->_BaseFormat,
+ texImage->TexFormat,
+ texImage->Data,
+ 0, 0, 0,
+ dstRowStride,
+ texImage->ImageOffsets,
+ width, height, 1,
+ format, type, src, packing)) {
_mesa_error(ctx, GL_OUT_OF_MEMORY, "glTexSubImage");
}
}
}
+done:
_mesa_unmap_teximage_pbo(ctx, packing);
-done:
if (stImage->pt) {
st_texture_image_unmap(ctx->st, stImage);
texImage->Data = NULL;
}
-
- if (level == texObj->BaseLevel && texObj->GenerateMipmap) {
- ctx->Driver.GenerateMipmap(ctx, target, texObj);
- }
}
struct pipe_transfer *src_trans;
GLvoid *texDest;
enum pipe_transfer_usage transfer_usage;
+
+ if (ST_DEBUG & DEBUG_FALLBACK)
+ debug_printf("%s: fallback processing\n", __FUNCTION__);
assert(width <= MAX_WIDTH);
srcX, srcY,
width, height);
- if (baseFormat == GL_DEPTH_COMPONENT &&
+ if ((baseFormat == GL_DEPTH_COMPONENT ||
+ baseFormat == GL_DEPTH_STENCIL) &&
pf_is_depth_and_stencil(stImage->pt->format))
transfer_usage = PIPE_TRANSFER_READ_WRITE;
else
destX, destY, width, height);
if (baseFormat == GL_DEPTH_COMPONENT ||
- baseFormat == GL_DEPTH24_STENCIL8) {
+ baseFormat == GL_DEPTH_STENCIL) {
const GLboolean scaleOrBias = (ctx->Pixel.DepthScale != 1.0F ||
ctx->Pixel.DepthBias != 0.0F);
GLint row, yStep;
* is actually RGBA but the user created the texture as GL_RGB we
* need to fill-in/override the alpha channel with 1.0.
*/
- texImage->TexFormat->StoreImage(ctx, dims,
- texImage->_BaseFormat,
- texImage->TexFormat,
- texDest,
- 0, 0, 0,
- dstRowStride,
- texImage->ImageOffsets,
- width, height, 1,
- GL_RGBA, GL_FLOAT, tempSrc, /* src */
- &unpack);
+ _mesa_texstore(ctx, dims,
+ texImage->_BaseFormat,
+ texImage->TexFormat,
+ texDest,
+ 0, 0, 0,
+ dstRowStride,
+ texImage->ImageOffsets,
+ width, height, 1,
+ GL_RGBA, GL_FLOAT, tempSrc, /* src */
+ &unpack);
}
else {
_mesa_error(ctx, GL_OUT_OF_MEMORY, "glTexSubImage");
}
+static unsigned
+compatible_src_dst_formats(const struct gl_renderbuffer *src,
+ const struct gl_texture_image *dst)
+{
+ const GLenum srcFormat = _mesa_get_format_base_format(src->Format);
+ const GLenum dstLogicalFormat = _mesa_get_format_base_format(dst->TexFormat);
+
+ if (srcFormat == dstLogicalFormat) {
+ /* This is the same as matching_base_formats, which should
+ * always pass, as it did previously.
+ */
+ return TGSI_WRITEMASK_XYZW;
+ }
+ else if (srcFormat == GL_RGBA &&
+ dstLogicalFormat == GL_RGB) {
+ /* Add a single special case to cope with RGBA->RGB transfers,
+ * setting A to 1.0 to cope with situations where the RGB
+ * destination is actually stored as RGBA.
+ */
+ return TGSI_WRITEMASK_XYZ; /* A ==> 1.0 */
+ }
+ else {
+ if (ST_DEBUG & DEBUG_FALLBACK)
+ debug_printf("%s failed for src %s, dst %s\n",
+ __FUNCTION__,
+ _mesa_lookup_enum_by_nr(srcFormat),
+ _mesa_lookup_enum_by_nr(dstLogicalFormat));
+
+ /* Otherwise fail.
+ */
+ return 0;
+ }
+}
+
+
+
/**
* 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
struct gl_texture_image *texImage =
_mesa_select_tex_image(ctx, texObj, target, level);
struct st_texture_image *stImage = st_texture_image(texImage);
- const GLenum texBaseFormat = texImage->InternalFormat;
+ const GLenum texBaseFormat = texImage->_BaseFormat;
struct gl_framebuffer *fb = ctx->ReadBuffer;
struct st_renderbuffer *strb;
struct pipe_context *pipe = ctx->st->pipe;
enum pipe_format dest_format, src_format;
GLboolean use_fallback = GL_TRUE;
GLboolean matching_base_formats;
+ GLuint format_writemask;
+ struct pipe_surface *dest_surface = NULL;
+ GLboolean do_flip = (st_fb_orientation(ctx->ReadBuffer) == Y_0_TOP);
/* any rendering in progress must flushed before we grab the fb image */
st_flush(ctx->st, PIPE_FLUSH_RENDER_CACHE, NULL);
/* determine if copying depth or color data */
if (texBaseFormat == GL_DEPTH_COMPONENT ||
- texBaseFormat == GL_DEPTH24_STENCIL8) {
+ texBaseFormat == GL_DEPTH_STENCIL) {
strb = st_renderbuffer(fb->_DepthBuffer);
}
- else if (texBaseFormat == GL_DEPTH_STENCIL_EXT) {
- strb = st_renderbuffer(fb->_StencilBuffer);
- }
else {
/* texBaseFormat == GL_RGB, GL_RGBA, GL_ALPHA, etc */
strb = st_renderbuffer(fb->_ColorReadBuffer);
* framebuffer's alpha values). We can't do that with the blit or
* textured-quad paths.
*/
- matching_base_formats = (strb->Base._BaseFormat == texImage->_BaseFormat);
+ matching_base_formats =
+ (_mesa_get_format_base_format(strb->Base.Format) ==
+ _mesa_get_format_base_format(texImage->TexFormat));
+ format_writemask = compatible_src_dst_formats(&strb->Base, texImage);
- if (matching_base_formats && ctx->_ImageTransferState == 0x0) {
- /* try potential hardware path */
- struct pipe_surface *dest_surface = NULL;
- boolean do_flip = (st_fb_orientation(ctx->ReadBuffer) == Y_0_TOP);
+ if (ctx->_ImageTransferState == 0x0) {
- if (src_format == dest_format && !do_flip) {
+ if (pipe->surface_copy &&
+ matching_base_formats &&
+ src_format == dest_format &&
+ !do_flip)
+ {
/* use surface_copy() / blit */
dest_surface = screen->get_tex_surface(screen, stImage->pt,
width, height);
use_fallback = GL_FALSE;
}
- else if (screen->is_format_supported(screen, src_format,
+ else if (format_writemask &&
+ texBaseFormat != GL_DEPTH_COMPONENT &&
+ texBaseFormat != GL_DEPTH_STENCIL &&
+ screen->is_format_supported(screen, src_format,
PIPE_TEXTURE_2D,
PIPE_TEXTURE_USAGE_SAMPLER,
0) &&
srcY0 = srcY;
srcY1 = srcY0 + height;
}
- util_blit_pixels(ctx->st->blit,
- strb->surface,
- srcX, srcY0,
- srcX + width, srcY1,
- dest_surface,
- destX, destY,
- destX + width, destY + height,
- 0.0, PIPE_TEX_MIPFILTER_NEAREST);
+ util_blit_pixels_writemask(ctx->st->blit,
+ strb->surface,
+ srcX, srcY0,
+ srcX + width, srcY1,
+ dest_surface,
+ destX, destY,
+ destX + width, destY + height,
+ 0.0, PIPE_TEX_MIPFILTER_NEAREST,
+ format_writemask);
use_fallback = GL_FALSE;
}
destX, destY, destZ,
srcX, srcY, width, height);
}
-
- if (level == texObj->BaseLevel && texObj->GenerateMipmap) {
- ctx->Driver.GenerateMipmap(ctx, target, texObj);
- }
}
}
-/**
- * Compute which mipmap levels that really need to be sent to the hardware.
- * This depends on the base image size, GL_TEXTURE_MIN_LOD,
- * GL_TEXTURE_MAX_LOD, GL_TEXTURE_BASE_LEVEL, and GL_TEXTURE_MAX_LEVEL.
- */
-static void
-calculate_first_last_level(struct st_texture_object *stObj)
-{
- struct gl_texture_object *tObj = &stObj->base;
-
- /* These must be signed values. MinLod and MaxLod can be negative numbers,
- * and having firstLevel and lastLevel as signed prevents the need for
- * extra sign checks.
- */
- GLint firstLevel;
- GLint lastLevel;
-
- /* Yes, this looks overly complicated, but it's all needed.
- */
- switch (tObj->Target) {
- case GL_TEXTURE_1D:
- case GL_TEXTURE_2D:
- case GL_TEXTURE_3D:
- case GL_TEXTURE_CUBE_MAP:
- if (tObj->MinFilter == GL_NEAREST || tObj->MinFilter == GL_LINEAR) {
- /* GL_NEAREST and GL_LINEAR only care about GL_TEXTURE_BASE_LEVEL.
- */
- firstLevel = lastLevel = tObj->BaseLevel;
- }
- else {
- firstLevel = 0;
- lastLevel = MIN2(tObj->MaxLevel,
- (int) tObj->Image[0][tObj->BaseLevel]->WidthLog2);
- }
- break;
- case GL_TEXTURE_RECTANGLE_NV:
- case GL_TEXTURE_4D_SGIS:
- firstLevel = lastLevel = 0;
- break;
- default:
- return;
- }
-
- stObj->lastLevel = lastLevel;
-}
-
-
static void
copy_image_data_to_texture(struct st_context *st,
struct st_texture_object *stObj,
*needFlush = GL_FALSE;
- /* We know/require this is true by now:
- */
- assert(stObj->base._Complete);
+ if (stObj->base._Complete) {
+ /* The texture is complete and we know exactly how many mipmap levels
+ * are present/needed. This is conditional because we may be called
+ * from the st_generate_mipmap() function when the texture object is
+ * incomplete. In that case, we'll have set stObj->lastLevel before
+ * we get here.
+ */
+ if (stObj->base.MinFilter == GL_LINEAR ||
+ stObj->base.MinFilter == GL_NEAREST)
+ stObj->lastLevel = stObj->base.BaseLevel;
+ else
+ stObj->lastLevel = stObj->base._MaxLevel - stObj->base.BaseLevel;
+ }
- /* What levels must the texture include at a minimum?
- */
- calculate_first_last_level(stObj);
firstImage = st_texture_image(stObj->base.Image[0][stObj->base.BaseLevel]);
/* If both firstImage and stObj point to a texture which can contain
}
/* FIXME: determine format block instead of cpp */
- if (firstImage->base.IsCompressed) {
- cpp = compressed_num_bytes(firstImage->base.TexFormat->MesaFormat);
+ if (_mesa_is_format_compressed(firstImage->base.TexFormat)) {
+ cpp = compressed_num_bytes(firstImage->base.TexFormat);
}
else {
- cpp = firstImage->base.TexFormat->TexelBytes;
+ cpp = _mesa_get_format_bytes(firstImage->base.TexFormat);
}
/* If we already have a gallium texture, check that it matches the texture
*/
if (stObj->pt) {
const enum pipe_format fmt =
- st_mesa_format_to_pipe_format(firstImage->base.TexFormat->MesaFormat);
+ st_mesa_format_to_pipe_format(firstImage->base.TexFormat);
if (stObj->pt->target != gl_target_to_pipe(stObj->base.Target) ||
stObj->pt->format != fmt ||
stObj->pt->last_level < stObj->lastLevel ||
*/
if (!stObj->pt) {
const enum pipe_format fmt =
- st_mesa_format_to_pipe_format(firstImage->base.TexFormat->MesaFormat);
+ st_mesa_format_to_pipe_format(firstImage->base.TexFormat);
GLuint usage = default_usage(fmt);
stObj->pt = st_texture_create(ctx->st,
/* compressed texture functions */
functions->CompressedTexImage2D = st_CompressedTexImage2D;
functions->GetCompressedTexImage = st_GetCompressedTexImage;
- functions->CompressedTextureSize = _mesa_compressed_texture_size;
functions->NewTextureObject = st_NewTextureObject;
functions->NewTextureImage = st_NewTextureImage;