blob: 628afc7a86b4c3a2635b50b46e4d62a42953a334 [file] [log] [blame]
Brian Paule4b23562005-05-04 20:11:35 +00001/*
2 * Mesa 3-D graphics library
Brian Paulf084f602005-09-13 23:37:50 +00003 * Version: 6.5
Brian Paule4b23562005-05-04 20:11:35 +00004 *
5 * Copyright (C) 1999-2005 Brian Paul All Rights Reserved.
6 *
7 * Permission is hereby granted, free of charge, to any person obtaining a
8 * copy of this software and associated documentation files (the "Software"),
9 * to deal in the Software without restriction, including without limitation
10 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
11 * and/or sell copies of the Software, and to permit persons to whom the
12 * Software is furnished to do so, subject to the following conditions:
13 *
14 * The above copyright notice and this permission notice shall be included
15 * in all copies or substantial portions of the Software.
16 *
17 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
18 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
20 * BRIAN PAUL BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
21 * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
22 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
23 */
24
25
26/**
27 * Functions for allocating/managing framebuffers and renderbuffers.
28 * Also, routines for reading/writing renderbuffer data as ubytes,
29 * ushorts, uints, etc.
30 */
31
32
33#include "glheader.h"
34#include "imports.h"
35#include "context.h"
36#include "mtypes.h"
37#include "fbobject.h"
38#include "framebuffer.h"
39#include "renderbuffer.h"
40
41
42
43/**
44 * Compute/set the _DepthMax field for the given framebuffer.
45 * This value depends on the Z buffer resolution.
46 */
47static void
48compute_depth_max(struct gl_framebuffer *fb)
49{
50 if (fb->Visual.depthBits == 0) {
51 /* Special case. Even if we don't have a depth buffer we need
52 * good values for DepthMax for Z vertex transformation purposes
53 * and for per-fragment fog computation.
54 */
55 fb->_DepthMax = (1 << 16) - 1;
56 }
57 else if (fb->Visual.depthBits < 32) {
58 fb->_DepthMax = (1 << fb->Visual.depthBits) - 1;
59 }
60 else {
61 /* Special case since shift values greater than or equal to the
62 * number of bits in the left hand expression's type are undefined.
63 */
64 fb->_DepthMax = 0xffffffff;
65 }
66 fb->_DepthMaxF = (GLfloat) fb->_DepthMax;
67 fb->_MRD = 1.0; /* Minimum resolvable depth value, for polygon offset */
68}
69
70
71/**
72 * Create and initialize a gl_framebuffer object.
73 * This is intended for creating _window_system_ framebuffers, not generic
74 * framebuffer objects ala GL_EXT_framebuffer_object.
75 *
76 * \sa _mesa_new_framebuffer
77 */
78struct gl_framebuffer *
79_mesa_create_framebuffer(const GLvisual *visual)
80{
81 struct gl_framebuffer *fb = CALLOC_STRUCT(gl_framebuffer);
82 assert(visual);
83 if (fb) {
84 _mesa_initialize_framebuffer(fb, visual);
85 }
86 return fb;
87}
88
89
90/**
91 * Allocate a new gl_framebuffer object.
92 * This is the default function for ctx->Driver.NewFramebuffer().
93 * This is for allocating user-created framebuffers, not window-system
94 * framebuffers!
95 * \sa _mesa_create_framebuffer
96 */
97struct gl_framebuffer *
98_mesa_new_framebuffer(GLcontext *ctx, GLuint name)
99{
100 struct gl_framebuffer *fb;
101 assert(name != 0);
102 fb = CALLOC_STRUCT(gl_framebuffer);
103 if (fb) {
104 fb->Name = name;
105 fb->RefCount = 1;
Brian Paule4b23562005-05-04 20:11:35 +0000106 fb->ColorDrawBuffer[0] = GL_COLOR_ATTACHMENT0_EXT;
107 fb->_ColorDrawBufferMask[0] = BUFFER_BIT_COLOR0;
108 fb->ColorReadBuffer = GL_COLOR_ATTACHMENT0_EXT;
109 fb->_ColorReadBufferMask = BUFFER_BIT_COLOR0;
110 fb->Delete = _mesa_destroy_framebuffer;
111 }
112 return fb;
113}
114
115
116/**
Brian Paulf084f602005-09-13 23:37:50 +0000117 * Initialize a gl_framebuffer object. Typically used to initialize
118 * window system-created framebuffers, not user-created framebuffers.
Brian Paule4b23562005-05-04 20:11:35 +0000119 * \sa _mesa_create_framebuffer
120 */
121void
122_mesa_initialize_framebuffer(struct gl_framebuffer *fb, const GLvisual *visual)
123{
124 assert(fb);
125 assert(visual);
126
127 _mesa_bzero(fb, sizeof(struct gl_framebuffer));
128
129 /* save the visual */
130 fb->Visual = *visual;
131
132 /* Init glRead/DrawBuffer state */
133 if (visual->doubleBufferMode) {
134 fb->ColorDrawBuffer[0] = GL_BACK;
135 fb->_ColorDrawBufferMask[0] = BUFFER_BIT_BACK_LEFT;
136 fb->ColorReadBuffer = GL_BACK;
137 fb->_ColorReadBufferMask = BUFFER_BIT_BACK_LEFT;
138 }
139 else {
140 fb->ColorDrawBuffer[0] = GL_FRONT;
141 fb->_ColorDrawBufferMask[0] = BUFFER_BIT_FRONT_LEFT;
142 fb->ColorReadBuffer = GL_FRONT;
143 fb->_ColorReadBufferMask = BUFFER_BIT_FRONT_LEFT;
144 }
145
146 fb->Delete = _mesa_destroy_framebuffer;
147
148 compute_depth_max(fb);
149}
150
151
152/**
Brian Paule4b23562005-05-04 20:11:35 +0000153 * Deallocate buffer and everything attached to it.
Brian Paulf084f602005-09-13 23:37:50 +0000154 * Typically called via the gl_framebuffer->Delete() method.
Brian Paule4b23562005-05-04 20:11:35 +0000155 */
156void
Brian Paulf084f602005-09-13 23:37:50 +0000157_mesa_destroy_framebuffer(struct gl_framebuffer *fb)
Brian Paule4b23562005-05-04 20:11:35 +0000158{
Brian Paulf084f602005-09-13 23:37:50 +0000159 if (fb) {
160 _mesa_free_framebuffer_data(fb);
161 FREE(fb);
Brian Paule4b23562005-05-04 20:11:35 +0000162 }
163}
164
165
166/**
167 * Free all the data hanging off the given gl_framebuffer, but don't free
168 * the gl_framebuffer object itself.
169 */
170void
171_mesa_free_framebuffer_data(struct gl_framebuffer *fb)
172{
173 GLuint i;
174
175 assert(fb);
176
177 for (i = 0; i < BUFFER_COUNT; i++) {
178 struct gl_renderbuffer_attachment *att = &fb->Attachment[i];
179 if (att->Type == GL_RENDERBUFFER_EXT && att->Renderbuffer) {
180 struct gl_renderbuffer *rb = att->Renderbuffer;
181 rb->RefCount--;
182 if (rb->RefCount == 0) {
183 rb->Delete(rb);
184 }
185 }
186 att->Type = GL_NONE;
187 att->Renderbuffer = NULL;
188 }
189}
190
191
192/**
193 * Resize the given framebuffer's renderbuffers to the new width and height.
194 * This should only be used for window-system framebuffers, not
195 * user-created renderbuffers (i.e. made with GL_EXT_framebuffer_object).
196 * This will typically be called via ctx->Driver.ResizeBuffers()
197 */
198void
199_mesa_resize_framebuffer(GLcontext *ctx, struct gl_framebuffer *fb,
200 GLuint width, GLuint height)
201{
202 GLuint i;
203
204 /* For window system framebuffers, Name is zero */
205 assert(fb->Name == 0);
206
207 for (i = 0; i < BUFFER_COUNT; i++) {
208 struct gl_renderbuffer_attachment *att = &fb->Attachment[i];
209 if (att->Type == GL_RENDERBUFFER_EXT && att->Renderbuffer) {
210 struct gl_renderbuffer *rb = att->Renderbuffer;
211 /* only resize if size is changing */
212 if (rb->Width != width || rb->Height != height) {
213 if (rb->AllocStorage(ctx, rb, rb->InternalFormat, width, height)) {
214 rb->Width = width;
215 rb->Height = height;
216 }
217 else {
218 _mesa_error(ctx, GL_OUT_OF_MEMORY, "Resizing framebuffer");
219 }
220 }
221 }
222 }
223
224 fb->Width = width;
225 fb->Height = height;
226}
227
228
229/**
230 * Examine all the framebuffer's renderbuffers to update the Width/Height
231 * fields of the framebuffer. If we have renderbuffers with different
232 * sizes, set the framebuffer's width and height to zero.
233 * Note: this is only intended for user-created framebuffers, not
234 * window-system framebuffes.
235 */
236static void
237update_framebuffer_size(struct gl_framebuffer *fb)
238{
239 GLboolean haveSize = GL_FALSE;
240 GLuint i;
241
242 /* user-created framebuffers only */
243 assert(fb->Name);
244
245 for (i = 0; i < BUFFER_COUNT; i++) {
246 struct gl_renderbuffer_attachment *att = &fb->Attachment[i];
247 const struct gl_renderbuffer *rb = att->Renderbuffer;
248 if (rb) {
249 if (haveSize) {
250 if (rb->Width != fb->Width && rb->Height != fb->Height) {
251 /* size mismatch! */
252 fb->Width = 0;
253 fb->Height = 0;
254 return;
255 }
256 }
257 else {
258 fb->Width = rb->Width;
259 fb->Height = rb->Height;
260 haveSize = GL_TRUE;
261 }
262 }
263 }
264}
265
266
267/**
268 * Update the context's current drawing buffer's Xmin, Xmax, Ymin, Ymax fields.
269 * These values are computed from the buffer's width and height and
270 * the scissor box, if it's enabled.
271 * \param ctx the GL context.
272 */
273void
274_mesa_update_draw_buffer_bounds(GLcontext *ctx)
275{
276 struct gl_framebuffer *buffer = ctx->DrawBuffer;
277
278 if (buffer->Name) {
279 /* user-created framebuffer size depends on the renderbuffers */
280 update_framebuffer_size(buffer);
281 }
282
283 buffer->_Xmin = 0;
284 buffer->_Ymin = 0;
285 buffer->_Xmax = buffer->Width;
286 buffer->_Ymax = buffer->Height;
287
288 if (ctx->Scissor.Enabled) {
289 if (ctx->Scissor.X > buffer->_Xmin) {
290 buffer->_Xmin = ctx->Scissor.X;
291 }
292 if (ctx->Scissor.Y > buffer->_Ymin) {
293 buffer->_Ymin = ctx->Scissor.Y;
294 }
295 if (ctx->Scissor.X + ctx->Scissor.Width < buffer->_Xmax) {
296 buffer->_Xmax = ctx->Scissor.X + ctx->Scissor.Width;
297 }
298 if (ctx->Scissor.Y + ctx->Scissor.Height < buffer->_Ymax) {
299 buffer->_Ymax = ctx->Scissor.Y + ctx->Scissor.Height;
300 }
301 /* finally, check for empty region */
302 if (buffer->_Xmin > buffer->_Xmax) {
303 buffer->_Xmin = buffer->_Xmax;
304 }
305 if (buffer->_Ymin > buffer->_Ymax) {
306 buffer->_Ymin = buffer->_Ymax;
307 }
308 }
309
310 ASSERT(buffer->_Xmin <= buffer->_Xmax);
311 ASSERT(buffer->_Ymin <= buffer->_Ymax);
312}
313
314
315/**
316 * The glGet queries of the framebuffer red/green/blue size, stencil size,
317 * etc. are satisfied by the fields of ctx->DrawBuffer->Visual. These can
Brian Paulf084f602005-09-13 23:37:50 +0000318 * change depending on the renderbuffer bindings. This function updates
Brian Paule4b23562005-05-04 20:11:35 +0000319 * the given framebuffer's Visual from the current renderbuffer bindings.
320 * This is only intended for user-created framebuffers.
321 */
322void
323_mesa_update_framebuffer_visual(struct gl_framebuffer *fb)
324{
325 assert(fb->Name != 0);
326
327 _mesa_bzero(&fb->Visual, sizeof(fb->Visual));
328 fb->Visual.rgbMode = GL_TRUE;
329
330 if (fb->Attachment[BUFFER_FRONT_LEFT].Renderbuffer) {
331 fb->Visual.redBits
332 = fb->Attachment[BUFFER_FRONT_LEFT].Renderbuffer->ComponentSizes[0];
333 fb->Visual.greenBits
334 = fb->Attachment[BUFFER_FRONT_LEFT].Renderbuffer->ComponentSizes[1];
335 fb->Visual.blueBits
336 = fb->Attachment[BUFFER_FRONT_LEFT].Renderbuffer->ComponentSizes[2];
337 fb->Visual.alphaBits
338 = fb->Attachment[BUFFER_FRONT_LEFT].Renderbuffer->ComponentSizes[3];
339 fb->Visual.rgbBits
340 = fb->Visual.redBits + fb->Visual.greenBits + fb->Visual.blueBits;
341 fb->Visual.floatMode = GL_FALSE;
342 }
343
344 if (fb->Attachment[BUFFER_DEPTH].Renderbuffer) {
345 fb->Visual.haveDepthBuffer = GL_TRUE;
346 fb->Visual.depthBits
347 = fb->Attachment[BUFFER_DEPTH].Renderbuffer->ComponentSizes[0];
348 }
349
350 if (fb->Attachment[BUFFER_STENCIL].Renderbuffer) {
351 fb->Visual.haveStencilBuffer = GL_TRUE;
352 fb->Visual.stencilBits
353 = fb->Attachment[BUFFER_STENCIL].Renderbuffer->ComponentSizes[0];
354 }
355
356 compute_depth_max(fb);
357}
358
359
360/**
361 * Given a framebuffer and a buffer bit (like BUFFER_BIT_FRONT_LEFT), return
362 * the corresponding renderbuffer.
363 */
364static struct gl_renderbuffer *
Brian Paule00ac112005-09-15 05:00:45 +0000365get_renderbuffer(struct gl_framebuffer *fb, GLbitfield bufferBit)
Brian Paule4b23562005-05-04 20:11:35 +0000366{
367 GLuint index;
368 for (index = 0; index < BUFFER_COUNT; index++) {
369 if ((1 << index) == bufferBit) {
370 return fb->Attachment[index].Renderbuffer;
371 }
372 }
373 _mesa_problem(NULL, "Bad bufferBit in get_renderbuffer");
374 return NULL;
375}
376
377
378/**
379 * Update state related to the current draw/read framebuffers.
Brian Paul52783592005-08-31 21:38:53 +0000380 * Specifically, update these framebuffer fields:
381 * _ColorDrawBuffers
Brian Paul52783592005-08-31 21:38:53 +0000382 * _NumColorDrawBuffers
383 * _ColorReadBuffer
Brian Paule4b23562005-05-04 20:11:35 +0000384 * If the current framebuffer is user-created, make sure it's complete.
Brian Paul52783592005-08-31 21:38:53 +0000385 * The following functions can effect this state: glReadBuffer,
386 * glDrawBuffer, glDrawBuffersARB, glFramebufferRenderbufferEXT.
Brian Paule4b23562005-05-04 20:11:35 +0000387 */
388void
389_mesa_update_framebuffer(GLcontext *ctx)
390{
391 struct gl_framebuffer *fb = ctx->DrawBuffer;
392 GLuint output;
393
394 /* Completeness only matters for user-created framebuffers */
395 if (fb->Name != 0)
396 _mesa_test_framebuffer_completeness(ctx, fb);
397
398 /*
399 * Update the list of drawing renderbuffer pointers.
400 * Later, when we're rendering we'll loop from 0 to _NumColorDrawBuffers
Brian Paulf084f602005-09-13 23:37:50 +0000401 * writing colors. We need the inner loop here because
402 * glDrawBuffer(GL_FRONT_AND_BACK) can specify writing to two or four
403 * color buffers (for example).
Brian Paule4b23562005-05-04 20:11:35 +0000404 */
405 for (output = 0; output < ctx->Const.MaxDrawBuffers; output++) {
Brian Paule00ac112005-09-15 05:00:45 +0000406 GLbitfield bufferMask = fb->_ColorDrawBufferMask[output];
Brian Paule4b23562005-05-04 20:11:35 +0000407 GLuint count = 0;
408 GLuint bufferBit;
409 /* for each bit that's set in the bufferMask... */
410 for (bufferBit = 1; bufferMask; bufferBit <<= 1) {
411 if (bufferBit & bufferMask) {
412 struct gl_renderbuffer *rb = get_renderbuffer(fb, bufferBit);
413 if (rb) {
414 fb->_ColorDrawBuffers[output][count] = rb;
Brian Paule4b23562005-05-04 20:11:35 +0000415 count++;
416 }
417 else {
418 _mesa_warning(ctx, "DrawBuffer names a missing buffer!");
419 }
420 bufferMask &= ~bufferBit;
421 }
422 }
423 fb->_NumColorDrawBuffers[output] = count;
424 }
425
426 /*
427 * Update the read renderbuffer pointer.
428 * Unlike the DrawBuffer, we can only read from one (or zero) color buffers.
429 */
430 if (fb->_ColorReadBufferMask == 0x0)
431 fb->_ColorReadBuffer = NULL; /* legal! */
432 else
433 fb->_ColorReadBuffer = get_renderbuffer(fb, fb->_ColorReadBufferMask);
434
435 compute_depth_max(fb);
436}