/************************************************************************** * * Copyright 2007 Tungsten Graphics, Inc., Cedar Park, Texas. * All Rights Reserved. * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the * "Software"), to deal in the Software without restriction, including * without limitation the rights to use, copy, modify, merge, publish, * distribute, sub license, and/or sell copies of the Software, and to * permit persons to whom the Software is furnished to do so, subject to * the following conditions: * * The above copyright notice and this permission notice (including the * next paragraph) shall be included in all copies or substantial portions * of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. * IN NO EVENT SHALL TUNGSTEN GRAPHICS AND/OR ITS SUPPLIERS BE LIABLE FOR * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. * **************************************************************************/ /** * Framebuffer/renderbuffer functions. * * \author Brian Paul */ #include "main/imports.h" #include "main/context.h" #include "main/fbobject.h" #include "main/framebuffer.h" #include "main/renderbuffer.h" #include "pipe/p_context.h" #include "pipe/p_defines.h" #include "st_context.h" #include "st_cb_fbo.h" #include "st_cb_teximage.h" /** * Derived renderbuffer class. Just need to add a pointer to the * pipe surface. */ struct st_renderbuffer { struct gl_renderbuffer Base; struct pipe_surface *surface; }; /** * Cast wrapper. */ static INLINE struct st_renderbuffer * st_renderbuffer(struct gl_renderbuffer *rb) { return (struct st_renderbuffer *) rb; } struct pipe_format_info { GLuint format; GLenum base_format; GLubyte red_bits; GLubyte green_bits; GLubyte blue_bits; GLubyte alpha_bits; GLubyte luminance_bits; GLubyte intensity_bits; GLubyte depth_bits; GLubyte stencil_bits; GLubyte size; /**< in bytes */ }; /* * XXX temporary here */ static const struct pipe_format_info * pipe_get_format_info(GLuint format) { static const struct pipe_format_info info[] = { { PIPE_FORMAT_U_R8_G8_B8_A8, /* format */ GL_RGBA, /* base_format */ 4, 4, 4, 4, 0, 0, /* color bits */ 0, 0, /* depth, stencil */ 4 /* size in bytes */ }, { PIPE_FORMAT_U_A8_R8_G8_B8, GL_RGBA, /* base_format */ 4, 4, 4, 4, 0, 0, /* color bits */ 0, 0, /* depth, stencil */ 4 /* size in bytes */ }, { PIPE_FORMAT_U_A1_R5_G5_B5, GL_RGBA, /* base_format */ 5, 5, 5, 1, 0, 0, /* color bits */ 0, 0, /* depth, stencil */ 2 /* size in bytes */ }, { PIPE_FORMAT_U_R5_G6_B5, GL_RGBA, /* base_format */ 5, 6, 5, 0, 0, 0, /* color bits */ 0, 0, /* depth, stencil */ 2 /* size in bytes */ }, /* XXX lots more */ { PIPE_FORMAT_S8_Z24, GL_DEPTH_STENCIL_EXT, /* base_format */ 0, 0, 0, 0, 0, 0, /* color bits */ 24, 8, /* depth, stencil */ 4 /* size in bytes */ } }; GLuint i; for (i = 0; i < sizeof(info) / sizeof(info[0]); i++) { if (info[i].format == format) return info + i; } return NULL; } /** * gl_renderbuffer::AllocStorage() */ static GLboolean st_renderbuffer_alloc_storage(GLcontext * ctx, struct gl_renderbuffer *rb, GLenum internalFormat, GLuint width, GLuint height) { struct pipe_context *pipe = ctx->st->pipe; struct st_renderbuffer *strb = st_renderbuffer(rb); const GLuint pipeFormat = st_choose_pipe_format(pipe, internalFormat, GL_NONE, GL_NONE); const struct pipe_format_info *info = pipe_get_format_info(pipeFormat); GLuint cpp, pitch; if (!info) return GL_FALSE; strb->Base._ActualFormat = info->base_format; strb->Base.DataType = GL_UNSIGNED_BYTE; /* XXX fix */ strb->Base.RedBits = info->red_bits; strb->Base.GreenBits = info->green_bits; strb->Base.BlueBits = info->blue_bits; strb->Base.AlphaBits = info->alpha_bits; strb->Base.DepthBits = info->depth_bits; strb->Base.StencilBits = info->stencil_bits; cpp = info->size; if (!strb->surface) { strb->surface = pipe->surface_alloc(pipe, pipeFormat); if (!strb->surface) return GL_FALSE; } /* free old region */ if (strb->surface->region) { pipe->region_release(pipe, &strb->surface->region); } /* Choose a pitch to match hardware requirements: */ pitch = ((cpp * width + 63) & ~63) / cpp; /* XXX fix: device-specific */ strb->surface->region = pipe->region_alloc(pipe, cpp, pitch, height); if (!strb->surface->region) return GL_FALSE; /* out of memory, try s/w buffer? */ ASSERT(strb->surface->region->buffer); strb->Base.Width = strb->surface->width = width; strb->Base.Height = strb->surface->height = height; return GL_TRUE; } /** * gl_renderbuffer::Delete() */ static void st_renderbuffer_delete(struct gl_renderbuffer *rb) { GET_CURRENT_CONTEXT(ctx); struct pipe_context *pipe = ctx->st->pipe; struct st_renderbuffer *strb = st_renderbuffer(rb); ASSERT(strb); if (strb && strb->surface) { if (rb->surface->region) { pipe->region_release(pipe, &strb->surface->region); } free(strb->surface); } free(strb); } /** * gl_renderbuffer::GetPointer() */ static void * null_get_pointer(GLcontext * ctx, struct gl_renderbuffer *rb, GLint x, GLint y) { /* By returning NULL we force all software rendering to go through * the span routines. */ assert(0); /* Should never get called with softpipe */ return NULL; } /** * Called via ctx->Driver.NewFramebuffer() */ static struct gl_framebuffer * st_new_framebuffer(GLcontext *ctx, GLuint name) { /* XXX not sure we need to subclass gl_framebuffer for pipe */ return _mesa_new_framebuffer(ctx, name); } /** * Called via ctx->Driver.NewRenderbuffer() */ static struct gl_renderbuffer * st_new_renderbuffer(GLcontext *ctx, GLuint name) { struct st_renderbuffer *strb = CALLOC_STRUCT(st_renderbuffer); if (strb) { _mesa_init_renderbuffer(&strb->Base, name); strb->Base.Delete = st_renderbuffer_delete; strb->Base.AllocStorage = st_renderbuffer_alloc_storage; strb->Base.GetPointer = null_get_pointer; return &strb->Base; } return NULL; } /** * Called via ctx->Driver.BindFramebufferEXT(). */ static void st_bind_framebuffer(GLcontext *ctx, GLenum target, struct gl_framebuffer *fb, struct gl_framebuffer *fbread) { } /** * Called by ctx->Driver.FramebufferRenderbuffer */ static void st_framebuffer_renderbuffer(GLcontext *ctx, struct gl_framebuffer *fb, GLenum attachment, struct gl_renderbuffer *rb) { /* XXX no need for derivation? */ _mesa_framebuffer_renderbuffer(ctx, fb, attachment, rb); } /** * Called by ctx->Driver.RenderTexture */ static void st_render_texture(GLcontext *ctx, struct gl_framebuffer *fb, struct gl_renderbuffer_attachment *att) { struct st_context *st = ctx->st; struct pipe_framebuffer_state framebuffer; struct pipe_surface *texsurface; texsurface = NULL; /* find the mipmap level, cube face, etc */ /* * XXX basically like this... set the current color (or depth) * drawing surface to be the given texture renderbuffer. */ memset(&framebuffer, 0, sizeof(framebuffer)); framebuffer.num_cbufs = 1; framebuffer.cbufs[0] = texsurface; if (memcmp(&framebuffer, &st->state.framebuffer, sizeof(framebuffer)) != 0) { st->state.framebuffer = framebuffer; st->pipe->set_framebuffer_state( st->pipe, &framebuffer ); } } /** * Called via ctx->Driver.FinishRenderTexture. */ static void st_finish_render_texture(GLcontext *ctx, struct gl_renderbuffer_attachment *att) { /* restore drawing to normal framebuffer. may be a no-op */ } void st_init_cb_fbo( struct st_context *st ) { struct dd_function_table *functions = &st->ctx->Driver; functions->NewFramebuffer = st_new_framebuffer; functions->NewRenderbuffer = st_new_renderbuffer; functions->BindFramebuffer = st_bind_framebuffer; functions->FramebufferRenderbuffer = st_framebuffer_renderbuffer; functions->RenderTexture = st_render_texture; functions->FinishRenderTexture = st_finish_render_texture; /* no longer needed by core Mesa, drivers handle resizes... functions->ResizeBuffers = st_resize_buffers; */ } void st_destroy_cb_fbo( struct st_context *st ) { }