**************************************************************************/
-#include "imports.h"
-#include "mtypes.h"
-#include "fbobject.h"
-#include "framebuffer.h"
-#include "renderbuffer.h"
-#include "context.h"
-#include "texformat.h"
-#include "texrender.h"
+#include "main/enums.h"
+#include "main/imports.h"
+#include "main/macros.h"
+#include "main/mtypes.h"
+#include "main/fbobject.h"
+#include "main/framebuffer.h"
+#include "main/renderbuffer.h"
+#include "main/context.h"
+#include "main/teximage.h"
+#include "main/image.h"
+
+#include "swrast/swrast.h"
+#include "drivers/common/meta.h"
#include "intel_context.h"
+#include "intel_batchbuffer.h"
#include "intel_buffers.h"
-#include "intel_depthstencil.h"
+#include "intel_blit.h"
#include "intel_fbo.h"
#include "intel_mipmap_tree.h"
#include "intel_regions.h"
-#include "intel_span.h"
-
+#include "intel_tex.h"
#define FILE_DEBUG_FLAG DEBUG_FBO
-#define INTEL_RB_CLASS 0x12345678
-
-
-/* XXX FBO: move this to intel_context.h (inlined) */
-/**
- * Return a gl_renderbuffer ptr casted to intel_renderbuffer.
- * NULL will be returned if the rb isn't really an intel_renderbuffer.
- * This is determiend by checking the ClassID.
- */
-struct intel_renderbuffer *
-intel_renderbuffer(struct gl_renderbuffer *rb)
-{
- struct intel_renderbuffer *irb = (struct intel_renderbuffer *) rb;
- if (irb && irb->Base.ClassID == INTEL_RB_CLASS) {
- /*_mesa_warning(NULL, "Returning non-intel Rb\n");*/
- return irb;
- }
- else
- return NULL;
-}
-
-
-struct intel_renderbuffer *
-intel_get_renderbuffer(struct gl_framebuffer *fb, GLuint attIndex)
-{
- return intel_renderbuffer(fb->Attachment[attIndex].Renderbuffer);
-}
-
-
-void
-intel_flip_renderbuffers(struct intel_framebuffer *intel_fb)
-{
- int current_page = intel_fb->pf_current_page;
- int next_page = (current_page + 1) % intel_fb->pf_num_pages;
- struct gl_renderbuffer *tmp_rb;
-
- /* Exchange renderbuffers if necessary but make sure their reference counts
- * are preserved.
- */
- if (intel_fb->color_rb[current_page] &&
- intel_fb->Base.Attachment[BUFFER_FRONT_LEFT].Renderbuffer !=
- &intel_fb->color_rb[current_page]->Base) {
- tmp_rb = NULL;
- _mesa_reference_renderbuffer(&tmp_rb,
- intel_fb->Base.Attachment[BUFFER_FRONT_LEFT].Renderbuffer);
- tmp_rb = &intel_fb->color_rb[current_page]->Base;
- _mesa_reference_renderbuffer(
- &intel_fb->Base.Attachment[BUFFER_FRONT_LEFT].Renderbuffer, tmp_rb);
- _mesa_reference_renderbuffer(&tmp_rb, NULL);
- }
-
- if (intel_fb->color_rb[next_page] &&
- intel_fb->Base.Attachment[BUFFER_BACK_LEFT].Renderbuffer !=
- &intel_fb->color_rb[next_page]->Base) {
- tmp_rb = NULL;
- _mesa_reference_renderbuffer(&tmp_rb,
- intel_fb->Base.Attachment[BUFFER_BACK_LEFT].Renderbuffer);
- tmp_rb = &intel_fb->color_rb[next_page]->Base;
- _mesa_reference_renderbuffer(
- &intel_fb->Base.Attachment[BUFFER_BACK_LEFT].Renderbuffer, tmp_rb);
- _mesa_reference_renderbuffer(&tmp_rb, NULL);
- }
-}
-
+static struct gl_renderbuffer *
+intel_new_renderbuffer(struct gl_context * ctx, GLuint name);
-struct intel_region *
+struct intel_region*
intel_get_rb_region(struct gl_framebuffer *fb, GLuint attIndex)
{
struct intel_renderbuffer *irb = intel_get_renderbuffer(fb, attIndex);
-
- if (irb)
- return irb->region;
+ if (irb && irb->mt)
+ return irb->mt->region;
else
return NULL;
}
-
-
/**
* Create a new framebuffer object.
*/
static struct gl_framebuffer *
-intel_new_framebuffer(GLcontext * ctx, GLuint name)
+intel_new_framebuffer(struct gl_context * ctx, GLuint name)
{
/* Only drawable state in intel_framebuffer at this time, just use Mesa's
* class
}
+/** Called by gl_renderbuffer::Delete() */
static void
-intel_delete_renderbuffer(struct gl_renderbuffer *rb)
+intel_delete_renderbuffer(struct gl_context *ctx, struct gl_renderbuffer *rb)
{
- GET_CURRENT_CONTEXT(ctx);
- struct intel_context *intel = intel_context(ctx);
struct intel_renderbuffer *irb = intel_renderbuffer(rb);
ASSERT(irb);
- if (irb->PairedStencil || irb->PairedDepth) {
- intel_unpair_depth_stencil(ctx, irb);
+ intel_miptree_release(&irb->mt);
+
+ _mesa_delete_renderbuffer(ctx, rb);
+}
+
+/**
+ * \see dd_function_table::MapRenderbuffer
+ */
+static void
+intel_map_renderbuffer(struct gl_context *ctx,
+ struct gl_renderbuffer *rb,
+ GLuint x, GLuint y, GLuint w, GLuint h,
+ GLbitfield mode,
+ GLubyte **out_map,
+ GLint *out_stride)
+{
+ struct intel_context *intel = intel_context(ctx);
+ struct swrast_renderbuffer *srb = (struct swrast_renderbuffer *)rb;
+ struct intel_renderbuffer *irb = intel_renderbuffer(rb);
+ void *map;
+ int stride;
+
+ if (srb->Buffer) {
+ /* this is a malloc'd renderbuffer (accum buffer), not an irb */
+ GLint bpp = _mesa_get_format_bytes(rb->Format);
+ GLint rowStride = srb->RowStride;
+ *out_map = (GLubyte *) srb->Buffer + y * rowStride + x * bpp;
+ *out_stride = rowStride;
+ return;
}
- if (intel && irb->region) {
- intel_region_release(&irb->region);
+ intel_prepare_render(intel);
+
+ /* For a window-system renderbuffer, we need to flip the mapping we receive
+ * upside-down. So we need to ask for a rectangle on flipped vertically, and
+ * we then return a pointer to the bottom of it with a negative stride.
+ */
+ if (rb->Name == 0) {
+ y = rb->Height - y - h;
}
- _mesa_free(irb);
-}
+ intel_miptree_map(intel, irb->mt, irb->mt_level, irb->mt_layer,
+ x, y, w, h, mode, &map, &stride);
+ if (rb->Name == 0) {
+ map += (h - 1) * stride;
+ stride = -stride;
+ }
+ DBG("%s: rb %d (%s) mt mapped: (%d, %d) (%dx%d) -> %p/%d\n",
+ __FUNCTION__, rb->Name, _mesa_get_format_name(rb->Format),
+ x, y, w, h, map, stride);
+
+ *out_map = map;
+ *out_stride = stride;
+}
/**
- * Return a pointer to a specific pixel in a renderbuffer.
+ * \see dd_function_table::UnmapRenderbuffer
*/
-static void *
-intel_get_pointer(GLcontext * ctx, struct gl_renderbuffer *rb,
- GLint x, GLint y)
+static void
+intel_unmap_renderbuffer(struct gl_context *ctx,
+ struct gl_renderbuffer *rb)
{
- /* By returning NULL we force all software rendering to go through
- * the span routines.
- */
- return NULL;
-}
+ struct intel_context *intel = intel_context(ctx);
+ struct swrast_renderbuffer *srb = (struct swrast_renderbuffer *)rb;
+ struct intel_renderbuffer *irb = intel_renderbuffer(rb);
+ DBG("%s: rb %d (%s)\n", __FUNCTION__,
+ rb->Name, _mesa_get_format_name(rb->Format));
+ if (srb->Buffer) {
+ /* this is a malloc'd renderbuffer (accum buffer) */
+ /* nothing to do */
+ return;
+ }
+
+ intel_miptree_unmap(intel, irb->mt, irb->mt_level, irb->mt_layer);
+}
/**
* Called via glRenderbufferStorageEXT() to set the format and allocate
* storage for a user-created renderbuffer.
*/
static GLboolean
-intel_alloc_renderbuffer_storage(GLcontext * ctx, struct gl_renderbuffer *rb,
+intel_alloc_renderbuffer_storage(struct gl_context * ctx, struct gl_renderbuffer *rb,
GLenum internalFormat,
GLuint width, GLuint height)
{
struct intel_context *intel = intel_context(ctx);
struct intel_renderbuffer *irb = intel_renderbuffer(rb);
- GLboolean softwareBuffer = GL_FALSE;
- int cpp;
-
- ASSERT(rb->Name != 0);
switch (internalFormat) {
- case GL_R3_G3_B2:
- case GL_RGB4:
- case GL_RGB5:
- rb->_ActualFormat = GL_RGB5;
- rb->DataType = GL_UNSIGNED_BYTE;
- rb->RedBits = 5;
- rb->GreenBits = 6;
- rb->BlueBits = 5;
- cpp = 2;
- break;
- case GL_RGB:
- case GL_RGB8:
- case GL_RGB10:
- case GL_RGB12:
- case GL_RGB16:
- case GL_RGBA:
- case GL_RGBA2:
- case GL_RGBA4:
- case GL_RGB5_A1:
- case GL_RGBA8:
- case GL_RGB10_A2:
- case GL_RGBA12:
- case GL_RGBA16:
- rb->_ActualFormat = GL_RGBA8;
- rb->DataType = GL_UNSIGNED_BYTE;
- rb->RedBits = 8;
- rb->GreenBits = 8;
- rb->BlueBits = 8;
- rb->AlphaBits = 8;
- cpp = 4;
+ default:
+ /* Use the same format-choice logic as for textures.
+ * Renderbuffers aren't any different from textures for us,
+ * except they're less useful because you can't texture with
+ * them.
+ */
+ rb->Format = intel->ctx.Driver.ChooseTextureFormat(ctx, GL_TEXTURE_2D,
+ internalFormat,
+ GL_NONE, GL_NONE);
break;
case GL_STENCIL_INDEX:
case GL_STENCIL_INDEX1_EXT:
case GL_STENCIL_INDEX4_EXT:
case GL_STENCIL_INDEX8_EXT:
case GL_STENCIL_INDEX16_EXT:
- /* alloc a depth+stencil buffer */
- rb->_ActualFormat = GL_DEPTH24_STENCIL8_EXT;
- rb->DataType = GL_UNSIGNED_INT_24_8_EXT;
- rb->StencilBits = 8;
- cpp = 4;
- break;
- case GL_DEPTH_COMPONENT16:
- rb->_ActualFormat = GL_DEPTH_COMPONENT16;
- rb->DataType = GL_UNSIGNED_SHORT;
- rb->DepthBits = 16;
- cpp = 2;
+ /* These aren't actual texture formats, so force them here. */
+ rb->Format = MESA_FORMAT_S8_Z24;
break;
- case GL_DEPTH_COMPONENT:
- case GL_DEPTH_COMPONENT24:
- case GL_DEPTH_COMPONENT32:
- rb->_ActualFormat = GL_DEPTH24_STENCIL8_EXT;
- rb->DataType = GL_UNSIGNED_INT_24_8_EXT;
- rb->DepthBits = 24;
- cpp = 4;
- break;
- case GL_DEPTH_STENCIL_EXT:
- case GL_DEPTH24_STENCIL8_EXT:
- rb->_ActualFormat = GL_DEPTH24_STENCIL8_EXT;
- rb->DataType = GL_UNSIGNED_INT_24_8_EXT;
- rb->DepthBits = 24;
- rb->StencilBits = 8;
- cpp = 4;
- break;
- default:
- _mesa_problem(ctx,
- "Unexpected format in intel_alloc_renderbuffer_storage");
- return GL_FALSE;
}
- intelFlush(ctx);
+ rb->Width = width;
+ rb->Height = height;
+ rb->_BaseFormat = _mesa_base_fbo_format(ctx, internalFormat);
- /* free old region */
- if (irb->region) {
- intel_region_release(&irb->region);
- }
+ intel_miptree_release(&irb->mt);
- /* allocate new memory region/renderbuffer */
- if (softwareBuffer) {
- return _mesa_soft_renderbuffer_storage(ctx, rb, internalFormat,
- width, height);
- }
- else {
- /* Choose a pitch to match hardware requirements:
- */
- GLuint pitch = ((cpp * width + 63) & ~63) / cpp;
+ DBG("%s: %s: %s (%dx%d)\n", __FUNCTION__,
+ _mesa_lookup_enum_by_nr(internalFormat),
+ _mesa_get_format_name(rb->Format), width, height);
- /* alloc hardware renderbuffer */
- DBG("Allocating %d x %d Intel RBO (pitch %d)\n", width,
- height, pitch);
+ if (width == 0 || height == 0)
+ return true;
- irb->region = intel_region_alloc(intel->intelScreen, cpp, pitch, height);
- if (!irb->region)
- return GL_FALSE; /* out of memory? */
+ irb->mt = intel_miptree_create_for_renderbuffer(intel, rb->Format,
+ width, height);
+ if (!irb->mt)
+ return false;
- ASSERT(irb->region->buffer);
+ return true;
+}
- rb->Width = width;
- rb->Height = height;
- /* This sets the Get/PutRow/Value functions */
- intel_set_span_functions(&irb->Base);
+static void
+intel_image_target_renderbuffer_storage(struct gl_context *ctx,
+ struct gl_renderbuffer *rb,
+ void *image_handle)
+{
+ struct intel_context *intel = intel_context(ctx);
+ struct intel_renderbuffer *irb;
+ __DRIscreen *screen;
+ __DRIimage *image;
+
+ screen = intel->intelScreen->driScrnPriv;
+ image = screen->dri2.image->lookupEGLImage(screen, image_handle,
+ screen->loaderPrivate);
+ if (image == NULL)
+ return;
- return GL_TRUE;
+ /* __DRIimage is opaque to the core so it has to be checked here */
+ switch (image->format) {
+ case MESA_FORMAT_RGBA8888_REV:
+ _mesa_error(&intel->ctx, GL_INVALID_OPERATION,
+ "glEGLImageTargetRenderbufferStorage(unsupported image format");
+ return;
+ break;
+ default:
+ break;
}
-}
+ irb = intel_renderbuffer(rb);
+ intel_miptree_release(&irb->mt);
+ irb->mt = intel_miptree_create_for_bo(intel,
+ image->region->bo,
+ image->format,
+ image->offset,
+ image->region->width,
+ image->region->height,
+ image->region->pitch,
+ image->region->tiling);
+ if (!irb->mt)
+ return;
+ rb->InternalFormat = image->internal_format;
+ rb->Width = image->region->width;
+ rb->Height = image->region->height;
+ rb->Format = image->format;
+ rb->_BaseFormat = _mesa_base_fbo_format(&intel->ctx,
+ image->internal_format);
+ rb->NeedsFinishRenderTexture = true;
+}
/**
- * Called for each hardware renderbuffer when a _window_ is resized.
- * Just update fields.
- * Not used for user-created renderbuffers!
+ * Called by _mesa_resize_framebuffer() for each hardware renderbuffer when a
+ * window system framebuffer is resized.
+ *
+ * Any actual buffer reallocations for hardware renderbuffers (which would
+ * have triggered _mesa_resize_framebuffer()) were done by
+ * intel_process_dri2_buffer().
*/
static GLboolean
-intel_alloc_window_storage(GLcontext * ctx, struct gl_renderbuffer *rb,
+intel_alloc_window_storage(struct gl_context * ctx, struct gl_renderbuffer *rb,
GLenum internalFormat, GLuint width, GLuint height)
{
ASSERT(rb->Name == 0);
rb->Width = width;
rb->Height = height;
- rb->_ActualFormat = internalFormat;
-
- return GL_TRUE;
-}
-
-static void
-intel_resize_buffers(GLcontext *ctx, struct gl_framebuffer *fb,
- GLuint width, GLuint height)
-{
- struct intel_framebuffer *intel_fb = (struct intel_framebuffer*)fb;
- int i;
+ rb->InternalFormat = internalFormat;
- _mesa_resize_framebuffer(ctx, fb, width, height);
-
- fb->Initialized = GL_TRUE; /* XXX remove someday */
-
- if (fb->Name != 0) {
- return;
- }
-
- /* Make sure all window system renderbuffers are up to date */
- for (i = 0; i < 3; i++) {
- struct gl_renderbuffer *rb = &intel_fb->color_rb[i]->Base;
-
- /* only resize if size is changing */
- if (rb && (rb->Width != width || rb->Height != height)) {
- rb->AllocStorage(ctx, rb, rb->InternalFormat, width, height);
- }
- }
+ return true;
}
+/** Dummy function for gl_renderbuffer::AllocStorage() */
static GLboolean
-intel_nop_alloc_storage(GLcontext * ctx, struct gl_renderbuffer *rb,
+intel_nop_alloc_storage(struct gl_context * ctx, struct gl_renderbuffer *rb,
GLenum internalFormat, GLuint width, GLuint height)
{
_mesa_problem(ctx, "intel_op_alloc_storage should never be called.");
- return GL_FALSE;
+ return false;
}
-
-
/**
* Create a new intel_renderbuffer which corresponds to an on-screen window,
* not a user-created renderbuffer.
- * \param width the screen width
- * \param height the screen height
*/
struct intel_renderbuffer *
-intel_create_renderbuffer(GLenum intFormat, GLsizei width, GLsizei height,
- int offset, int pitch, int cpp, void *map)
+intel_create_renderbuffer(gl_format format)
{
- GET_CURRENT_CONTEXT(ctx);
-
struct intel_renderbuffer *irb;
- const GLuint name = 0;
+ struct gl_renderbuffer *rb;
+
+ GET_CURRENT_CONTEXT(ctx);
irb = CALLOC_STRUCT(intel_renderbuffer);
if (!irb) {
return NULL;
}
- _mesa_init_renderbuffer(&irb->Base, name);
- irb->Base.ClassID = INTEL_RB_CLASS;
-
- switch (intFormat) {
- case GL_RGB5:
- irb->Base._ActualFormat = GL_RGB5;
- irb->Base._BaseFormat = GL_RGBA;
- irb->Base.RedBits = 5;
- irb->Base.GreenBits = 6;
- irb->Base.BlueBits = 5;
- irb->Base.DataType = GL_UNSIGNED_BYTE;
- cpp = 2;
- break;
- case GL_RGBA8:
- irb->Base._ActualFormat = GL_RGBA8;
- irb->Base._BaseFormat = GL_RGBA;
- irb->Base.RedBits = 8;
- irb->Base.GreenBits = 8;
- irb->Base.BlueBits = 8;
- irb->Base.AlphaBits = 8;
- irb->Base.DataType = GL_UNSIGNED_BYTE;
- cpp = 4;
- break;
- case GL_STENCIL_INDEX8_EXT:
- irb->Base._ActualFormat = GL_STENCIL_INDEX8_EXT;
- irb->Base._BaseFormat = GL_STENCIL_INDEX;
- irb->Base.StencilBits = 8;
- irb->Base.DataType = GL_UNSIGNED_BYTE;
- cpp = 1;
- break;
- case GL_DEPTH_COMPONENT16:
- irb->Base._ActualFormat = GL_DEPTH_COMPONENT16;
- irb->Base._BaseFormat = GL_DEPTH_COMPONENT;
- irb->Base.DepthBits = 16;
- irb->Base.DataType = GL_UNSIGNED_SHORT;
- cpp = 2;
- break;
- case GL_DEPTH_COMPONENT24:
- irb->Base._ActualFormat = GL_DEPTH24_STENCIL8_EXT;
- irb->Base._BaseFormat = GL_DEPTH_COMPONENT;
- irb->Base.DepthBits = 24;
- irb->Base.DataType = GL_UNSIGNED_INT;
- cpp = 4;
- break;
- case GL_DEPTH24_STENCIL8_EXT:
- irb->Base._ActualFormat = GL_DEPTH24_STENCIL8_EXT;
- irb->Base._BaseFormat = GL_DEPTH_STENCIL_EXT;
- irb->Base.DepthBits = 24;
- irb->Base.StencilBits = 8;
- irb->Base.DataType = GL_UNSIGNED_INT_24_8_EXT;
- cpp = 4;
- break;
- default:
- _mesa_problem(NULL,
- "Unexpected intFormat in intel_create_renderbuffer");
- return NULL;
- }
+ rb = &irb->Base.Base;
- irb->Base.InternalFormat = intFormat;
+ _mesa_init_renderbuffer(rb, 0);
+ rb->ClassID = INTEL_RB_CLASS;
+ rb->_BaseFormat = _mesa_get_format_base_format(format);
+ rb->Format = format;
+ rb->InternalFormat = rb->_BaseFormat;
/* intel-specific methods */
- irb->Base.Delete = intel_delete_renderbuffer;
- irb->Base.AllocStorage = intel_alloc_window_storage;
- irb->Base.GetPointer = intel_get_pointer;
- /* This sets the Get/PutRow/Value functions */
- intel_set_span_functions(&irb->Base);
+ rb->Delete = intel_delete_renderbuffer;
+ rb->AllocStorage = intel_alloc_window_storage;
+
+ return irb;
+}
- irb->pfMap = map;
- irb->pfPitch = pitch / cpp; /* in pixels */
+/**
+ * Private window-system buffers (as opposed to ones shared with the display
+ * server created with intel_create_renderbuffer()) are most similar in their
+ * handling to user-created renderbuffers, but they have a resize handler that
+ * may be called at intel_update_renderbuffers() time.
+ */
+struct intel_renderbuffer *
+intel_create_private_renderbuffer(gl_format format)
+{
+ struct intel_renderbuffer *irb;
-#if 00
- irb->region = intel_region_create_static(intel,
- DRM_MM_TT,
- offset, map, cpp, width, height);
-#endif
+ irb = intel_create_renderbuffer(format);
+ irb->Base.Base.AllocStorage = intel_alloc_renderbuffer_storage;
return irb;
}
-
/**
* Create a new renderbuffer object.
* Typically called via glBindRenderbufferEXT().
*/
static struct gl_renderbuffer *
-intel_new_renderbuffer(GLcontext * ctx, GLuint name)
+intel_new_renderbuffer(struct gl_context * ctx, GLuint name)
{
/*struct intel_context *intel = intel_context(ctx); */
struct intel_renderbuffer *irb;
+ struct gl_renderbuffer *rb;
irb = CALLOC_STRUCT(intel_renderbuffer);
if (!irb) {
return NULL;
}
- _mesa_init_renderbuffer(&irb->Base, name);
- irb->Base.ClassID = INTEL_RB_CLASS;
+ rb = &irb->Base.Base;
+
+ _mesa_init_renderbuffer(rb, name);
+ rb->ClassID = INTEL_RB_CLASS;
/* intel-specific methods */
- irb->Base.Delete = intel_delete_renderbuffer;
- irb->Base.AllocStorage = intel_alloc_renderbuffer_storage;
- irb->Base.GetPointer = intel_get_pointer;
+ rb->Delete = intel_delete_renderbuffer;
+ rb->AllocStorage = intel_alloc_renderbuffer_storage;
/* span routines set in alloc_storage function */
- return &irb->Base;
+ return rb;
}
* Called via glBindFramebufferEXT().
*/
static void
-intel_bind_framebuffer(GLcontext * ctx, GLenum target,
+intel_bind_framebuffer(struct gl_context * ctx, GLenum target,
struct gl_framebuffer *fb, struct gl_framebuffer *fbread)
{
if (target == GL_FRAMEBUFFER_EXT || target == GL_DRAW_FRAMEBUFFER_EXT) {
- intel_draw_buffer(ctx, fb);
- /* Integer depth range depends on depth buffer bits */
- ctx->Driver.DepthRange(ctx, ctx->Viewport.Near, ctx->Viewport.Far);
+ intel_draw_buffer(ctx);
}
else {
/* don't need to do anything if target == GL_READ_FRAMEBUFFER_EXT */
* Called via glFramebufferRenderbufferEXT().
*/
static void
-intel_framebuffer_renderbuffer(GLcontext * ctx,
+intel_framebuffer_renderbuffer(struct gl_context * ctx,
struct gl_framebuffer *fb,
GLenum attachment, struct gl_renderbuffer *rb)
{
DBG("Intel FramebufferRenderbuffer %u %u\n", fb->Name, rb ? rb->Name : 0);
- intelFlush(ctx);
-
_mesa_framebuffer_renderbuffer(ctx, fb, attachment, rb);
- intel_draw_buffer(ctx, fb);
+ intel_draw_buffer(ctx);
}
-
-/**
- * When glFramebufferTexture[123]D is called this function sets up the
- * gl_renderbuffer wrapper around the texture image.
- * This will have the region info needed for hardware rendering.
- */
-static struct intel_renderbuffer *
-intel_wrap_texture(GLcontext * ctx, struct gl_texture_image *texImage)
+static bool
+intel_renderbuffer_update_wrapper(struct intel_context *intel,
+ struct intel_renderbuffer *irb,
+ struct gl_texture_image *image,
+ uint32_t layer)
{
- const GLuint name = ~0; /* not significant, but distinct for debugging */
- struct intel_renderbuffer *irb;
+ struct gl_renderbuffer *rb = &irb->Base.Base;
+ struct intel_texture_image *intel_image = intel_texture_image(image);
+ struct intel_mipmap_tree *mt = intel_image->mt;
+ int level = image->Level;
- /* make an intel_renderbuffer to wrap the texture image */
- irb = CALLOC_STRUCT(intel_renderbuffer);
- if (!irb) {
- _mesa_error(ctx, GL_OUT_OF_MEMORY, "glFramebufferTexture");
- return NULL;
- }
+ rb->Depth = image->Depth;
- _mesa_init_renderbuffer(&irb->Base, name);
- irb->Base.ClassID = INTEL_RB_CLASS;
+ rb->AllocStorage = intel_nop_alloc_storage;
- if (texImage->TexFormat == &_mesa_texformat_argb8888) {
- irb->Base._ActualFormat = GL_RGBA8;
- irb->Base._BaseFormat = GL_RGBA;
- DBG("Render to RGBA8 texture OK\n");
- }
- else if (texImage->TexFormat == &_mesa_texformat_rgb565) {
- irb->Base._ActualFormat = GL_RGB5;
- irb->Base._BaseFormat = GL_RGB;
- DBG("Render to RGB5 texture OK\n");
- }
- else if (texImage->TexFormat == &_mesa_texformat_z16) {
- irb->Base._ActualFormat = GL_DEPTH_COMPONENT16;
- irb->Base._BaseFormat = GL_DEPTH_COMPONENT;
- DBG("Render to DEPTH16 texture OK\n");
- }
- else {
- DBG("Render to texture BAD FORMAT %d\n",
- texImage->TexFormat->MesaFormat);
- _mesa_free(irb);
- return NULL;
- }
+ intel_miptree_check_level_layer(mt, level, layer);
+ irb->mt_level = level;
+ irb->mt_layer = layer;
- irb->Base.InternalFormat = irb->Base._ActualFormat;
- irb->Base.Width = texImage->Width;
- irb->Base.Height = texImage->Height;
- irb->Base.DataType = GL_UNSIGNED_BYTE; /* FBO XXX fix */
- irb->Base.RedBits = texImage->TexFormat->RedBits;
- irb->Base.GreenBits = texImage->TexFormat->GreenBits;
- irb->Base.BlueBits = texImage->TexFormat->BlueBits;
- irb->Base.AlphaBits = texImage->TexFormat->AlphaBits;
- irb->Base.DepthBits = texImage->TexFormat->DepthBits;
+ intel_miptree_reference(&irb->mt, mt);
- irb->Base.Delete = intel_delete_renderbuffer;
- irb->Base.AllocStorage = intel_nop_alloc_storage;
- intel_set_span_functions(&irb->Base);
+ intel_renderbuffer_set_draw_offset(irb);
- irb->RenderToTexture = GL_TRUE;
-
- return irb;
+ return true;
}
+void
+intel_renderbuffer_set_draw_offset(struct intel_renderbuffer *irb)
+{
+ unsigned int dst_x, dst_y;
+
+ /* compute offset of the particular 2D image within the texture region */
+ intel_miptree_get_image_offset(irb->mt,
+ irb->mt_level,
+ irb->mt_layer,
+ &dst_x, &dst_y);
+
+ irb->draw_x = dst_x;
+ irb->draw_y = dst_y;
+}
/**
* Called by glFramebufferTexture[123]DEXT() (and other places) to
* before intel_finish_render_texture() is ever called.
*/
static void
-intel_render_texture(GLcontext * ctx,
+intel_render_texture(struct gl_context * ctx,
struct gl_framebuffer *fb,
struct gl_renderbuffer_attachment *att)
{
- struct gl_texture_image *newImage
- = att->Texture->Image[att->CubeMapFace][att->TextureLevel];
- struct intel_renderbuffer *irb = intel_renderbuffer(att->Renderbuffer);
- struct intel_texture_image *intel_image;
- GLuint imageOffset;
+ struct intel_context *intel = intel_context(ctx);
+ struct gl_renderbuffer *rb = att->Renderbuffer;
+ struct intel_renderbuffer *irb = intel_renderbuffer(rb);
+ struct gl_texture_image *image = rb->TexImage;
+ struct intel_texture_image *intel_image = intel_texture_image(image);
+ struct intel_mipmap_tree *mt = intel_image->mt;
+ int layer;
(void) fb;
- ASSERT(newImage);
-
- if (!irb) {
- irb = intel_wrap_texture(ctx, newImage);
- if (irb) {
- /* bind the wrapper to the attachment point */
- _mesa_reference_renderbuffer(&att->Renderbuffer, &irb->Base);
- }
- else {
- /* fallback to software rendering */
- _mesa_render_texture(ctx, fb, att);
- return;
- }
+ if (att->CubeMapFace > 0) {
+ assert(att->Zoffset == 0);
+ layer = att->CubeMapFace;
+ } else {
+ layer = att->Zoffset;
}
- DBG("Begin render texture tid %x tex=%u w=%d h=%d refcount=%d\n",
- _glthread_GetID(),
- att->Texture->Name, newImage->Width, newImage->Height,
- irb->Base.RefCount);
-
- /* point the renderbufer's region to the texture image region */
- intel_image = intel_texture_image(newImage);
- if (irb->region != intel_image->mt->region) {
- if (irb->region)
- intel_region_release(&irb->region);
- intel_region_reference(&irb->region, intel_image->mt->region);
+ if (!intel_image->mt) {
+ /* Fallback on drawing to a texture that doesn't have a miptree
+ * (has a border, width/height 0, etc.)
+ */
+ _swrast_render_texture(ctx, fb, att);
+ return;
}
- /* compute offset of the particular 2D image within the texture region */
- imageOffset = intel_miptree_image_offset(intel_image->mt,
- att->CubeMapFace,
- att->TextureLevel);
-
- if (att->Texture->Target == GL_TEXTURE_3D) {
- const GLuint *offsets = intel_miptree_depth_offsets(intel_image->mt,
- att->TextureLevel);
- imageOffset += offsets[att->Zoffset];
+ intel_miptree_check_level_layer(mt, att->TextureLevel, layer);
+
+ if (!intel_renderbuffer_update_wrapper(intel, irb, image, layer)) {
+ _swrast_render_texture(ctx, fb, att);
+ return;
}
- /* store that offset in the region */
- intel_image->mt->region->draw_offset = imageOffset;
+ DBG("Begin render %s texture tex=%u w=%d h=%d d=%d refcount=%d\n",
+ _mesa_get_format_name(image->TexFormat),
+ att->Texture->Name, image->Width, image->Height, image->Depth,
+ rb->RefCount);
/* update drawing region, etc */
- intel_draw_buffer(ctx, fb);
+ intel_draw_buffer(ctx);
}
* Called by Mesa when rendering to a texture is done.
*/
static void
-intel_finish_render_texture(GLcontext * ctx,
- struct gl_renderbuffer_attachment *att)
+intel_finish_render_texture(struct gl_context * ctx, struct gl_renderbuffer *rb)
+{
+ struct intel_context *intel = intel_context(ctx);
+
+ DBG("Finish render %s texture\n", _mesa_get_format_name(rb->Format));
+
+ /* Since we've (probably) rendered to the texture and will (likely) use
+ * it in the texture domain later on in this batchbuffer, flush the
+ * batch. Once again, we wish for a domain tracker in libdrm to cover
+ * usage inside of a batchbuffer like GEM does in the kernel.
+ */
+ intel_batchbuffer_emit_mi_flush(intel);
+}
+
+#define fbo_incomplete(fb, ...) do { \
+ static GLuint msg_id = 0; \
+ if (unlikely(ctx->Const.ContextFlags & GL_CONTEXT_FLAG_DEBUG_BIT)) { \
+ _mesa_gl_debug(ctx, &msg_id, \
+ MESA_DEBUG_TYPE_OTHER, \
+ MESA_DEBUG_SEVERITY_MEDIUM, \
+ __VA_ARGS__); \
+ } \
+ DBG(__VA_ARGS__); \
+ fb->_Status = GL_FRAMEBUFFER_UNSUPPORTED; \
+ } while (0)
+
+/**
+ * Do additional "completeness" testing of a framebuffer object.
+ */
+static void
+intel_validate_framebuffer(struct gl_context *ctx, struct gl_framebuffer *fb)
{
- struct intel_renderbuffer *irb = intel_renderbuffer(att->Renderbuffer);
+ struct intel_context *intel = intel_context(ctx);
+ struct intel_renderbuffer *depthRb =
+ intel_get_renderbuffer(fb, BUFFER_DEPTH);
+ struct intel_renderbuffer *stencilRb =
+ intel_get_renderbuffer(fb, BUFFER_STENCIL);
+ struct intel_mipmap_tree *depth_mt = NULL, *stencil_mt = NULL;
+ int i;
+
+ DBG("%s() on fb %p (%s)\n", __FUNCTION__,
+ fb, (fb == ctx->DrawBuffer ? "drawbuffer" :
+ (fb == ctx->ReadBuffer ? "readbuffer" : "other buffer")));
+
+ if (depthRb)
+ depth_mt = depthRb->mt;
+ if (stencilRb)
+ stencil_mt = stencilRb->mt;
+
+ if (depth_mt && stencil_mt) {
+ /* Make sure that the depth and stencil buffers are actually the same
+ * slice of the same miptree, since we only support packed
+ * depth/stencil.
+ */
+ if (depth_mt == stencil_mt) {
+ if (depthRb->mt_level != stencilRb->mt_level ||
+ depthRb->mt_layer != stencilRb->mt_layer) {
+ fbo_incomplete(fb,
+ "FBO incomplete: depth image level/layer %d/%d != "
+ "stencil image %d/%d\n",
+ depthRb->mt_level,
+ depthRb->mt_layer,
+ stencilRb->mt_level,
+ stencilRb->mt_layer);
+ }
+ } else {
+ fbo_incomplete(fb, "FBO incomplete: separate stencil unsupported\n");
+ }
+ }
+
+ for (i = 0; i < Elements(fb->Attachment); i++) {
+ struct gl_renderbuffer *rb;
+ struct intel_renderbuffer *irb;
+
+ if (fb->Attachment[i].Type == GL_NONE)
+ continue;
+
+ /* A supported attachment will have a Renderbuffer set either
+ * from being a Renderbuffer or being a texture that got the
+ * intel_wrap_texture() treatment.
+ */
+ rb = fb->Attachment[i].Renderbuffer;
+ if (rb == NULL) {
+ fbo_incomplete(fb, "FBO incomplete: attachment without "
+ "renderbuffer\n");
+ continue;
+ }
- DBG("End render texture (tid %x) tex %u\n", _glthread_GetID(), att->Texture->Name);
+ if (fb->Attachment[i].Type == GL_TEXTURE) {
+ if (rb->TexImage->Border) {
+ fbo_incomplete(fb, "FBO incomplete: texture with border\n");
+ continue;
+ }
+ }
+
+ irb = intel_renderbuffer(rb);
+ if (irb == NULL) {
+ fbo_incomplete(fb, "FBO incomplete: software rendering "
+ "renderbuffer\n");
+ continue;
+ }
- if (irb) {
- /* just release the region */
- intel_region_release(&irb->region);
+ if (!intel->vtbl.render_target_supported(intel, rb)) {
+ fbo_incomplete(fb, "FBO incomplete: Unsupported HW "
+ "texture/renderbuffer format attached: %s\n",
+ _mesa_get_format_name(intel_rb_format(irb)));
+ }
}
- else if (att->Renderbuffer) {
- /* software fallback */
- _mesa_finish_render_texture(ctx, att);
- /* XXX FBO: Need to unmap the buffer (or in intelSpanRenderStart???) */
+}
+
+/**
+ * Try to do a glBlitFramebuffer using glCopyTexSubImage2D
+ * We can do this when the dst renderbuffer is actually a texture and
+ * there is no scaling, mirroring or scissoring.
+ *
+ * \return new buffer mask indicating the buffers left to blit using the
+ * normal path.
+ */
+static GLbitfield
+intel_blit_framebuffer_with_blitter(struct gl_context *ctx,
+ GLint srcX0, GLint srcY0,
+ GLint srcX1, GLint srcY1,
+ GLint dstX0, GLint dstY0,
+ GLint dstX1, GLint dstY1,
+ GLbitfield mask, GLenum filter)
+{
+ struct intel_context *intel = intel_context(ctx);
+
+ if (mask & GL_COLOR_BUFFER_BIT) {
+ GLint i;
+ const struct gl_framebuffer *drawFb = ctx->DrawBuffer;
+ const struct gl_framebuffer *readFb = ctx->ReadBuffer;
+ struct gl_renderbuffer *src_rb = readFb->_ColorReadBuffer;
+ struct intel_renderbuffer *src_irb = intel_renderbuffer(src_rb);
+
+ if (!src_irb) {
+ perf_debug("glBlitFramebuffer(): missing src renderbuffer. "
+ "Falling back to software rendering.\n");
+ return mask;
+ }
+
+ /* If the source and destination are the same size with no mirroring,
+ * the rectangles are within the size of the texture and there is no
+ * scissor, then we can probably use the blit engine.
+ */
+ if (!(srcX0 - srcX1 == dstX0 - dstX1 &&
+ srcY0 - srcY1 == dstY0 - dstY1 &&
+ srcX1 >= srcX0 &&
+ srcY1 >= srcY0 &&
+ srcX0 >= 0 && srcX1 <= readFb->Width &&
+ srcY0 >= 0 && srcY1 <= readFb->Height &&
+ dstX0 >= 0 && dstX1 <= drawFb->Width &&
+ dstY0 >= 0 && dstY1 <= drawFb->Height &&
+ !ctx->Scissor.Enabled)) {
+ perf_debug("glBlitFramebuffer(): non-1:1 blit. "
+ "Falling back to software rendering.\n");
+ return mask;
+ }
+
+ /* Blit to all active draw buffers. We don't do any pre-checking,
+ * because we assume that copying to MRTs is rare, and failure midway
+ * through copying is even more rare. Even if it was to occur, it's
+ * safe to let meta start the copy over from scratch, because
+ * glBlitFramebuffer completely overwrites the destination pixels, and
+ * results are undefined if any destination pixels have a dependency on
+ * source pixels.
+ */
+ for (i = 0; i < ctx->DrawBuffer->_NumColorDrawBuffers; i++) {
+ struct gl_renderbuffer *dst_rb = ctx->DrawBuffer->_ColorDrawBuffers[i];
+ struct intel_renderbuffer *dst_irb = intel_renderbuffer(dst_rb);
+
+ if (!dst_irb) {
+ perf_debug("glBlitFramebuffer(): missing dst renderbuffer. "
+ "Falling back to software rendering.\n");
+ return mask;
+ }
+
+ gl_format src_format = _mesa_get_srgb_format_linear(src_rb->Format);
+ gl_format dst_format = _mesa_get_srgb_format_linear(dst_rb->Format);
+ if (src_format != dst_format) {
+ perf_debug("glBlitFramebuffer(): unsupported blit from %s to %s. "
+ "Falling back to software rendering.\n",
+ _mesa_get_format_name(src_format),
+ _mesa_get_format_name(dst_format));
+ return mask;
+ }
+
+ if (!intel_miptree_blit(intel,
+ src_irb->mt,
+ src_irb->mt_level, src_irb->mt_layer,
+ srcX0, srcY0, src_rb->Name == 0,
+ dst_irb->mt,
+ dst_irb->mt_level, dst_irb->mt_layer,
+ dstX0, dstY0, dst_rb->Name == 0,
+ dstX1 - dstX0, dstY1 - dstY0, GL_COPY)) {
+ perf_debug("glBlitFramebuffer(): unknown blit failure. "
+ "Falling back to software rendering.\n");
+ return mask;
+ }
+ }
+
+ mask &= ~GL_COLOR_BUFFER_BIT;
}
+
+ return mask;
}
+static void
+intel_blit_framebuffer(struct gl_context *ctx,
+ GLint srcX0, GLint srcY0, GLint srcX1, GLint srcY1,
+ GLint dstX0, GLint dstY0, GLint dstX1, GLint dstY1,
+ GLbitfield mask, GLenum filter)
+{
+ /* Try using the BLT engine. */
+ mask = intel_blit_framebuffer_with_blitter(ctx,
+ srcX0, srcY0, srcX1, srcY1,
+ dstX0, dstY0, dstX1, dstY1,
+ mask, filter);
+ if (mask == 0x0)
+ return;
+
+
+ _mesa_meta_BlitFramebuffer(ctx,
+ srcX0, srcY0, srcX1, srcY1,
+ dstX0, dstY0, dstX1, dstY1,
+ mask, filter);
+}
/**
* Do one-time context initializations related to GL_EXT_framebuffer_object.
{
intel->ctx.Driver.NewFramebuffer = intel_new_framebuffer;
intel->ctx.Driver.NewRenderbuffer = intel_new_renderbuffer;
+ intel->ctx.Driver.MapRenderbuffer = intel_map_renderbuffer;
+ intel->ctx.Driver.UnmapRenderbuffer = intel_unmap_renderbuffer;
intel->ctx.Driver.BindFramebuffer = intel_bind_framebuffer;
intel->ctx.Driver.FramebufferRenderbuffer = intel_framebuffer_renderbuffer;
intel->ctx.Driver.RenderTexture = intel_render_texture;
intel->ctx.Driver.FinishRenderTexture = intel_finish_render_texture;
- intel->ctx.Driver.ResizeBuffers = intel_resize_buffers;
+ intel->ctx.Driver.ValidateFramebuffer = intel_validate_framebuffer;
+ intel->ctx.Driver.BlitFramebuffer = intel_blit_framebuffer;
+ intel->ctx.Driver.EGLImageTargetRenderbufferStorage =
+ intel_image_target_renderbuffer_storage;
}