1 /**************************************************************************
3 * Copyright 2006 Tungsten Graphics, Inc., Cedar Park, Texas.
6 * Permission is hereby granted, free of charge, to any person obtaining a
7 * copy of this software and associated documentation files (the
8 * "Software"), to deal in the Software without restriction, including
9 * without limitation the rights to use, copy, modify, merge, publish,
10 * distribute, sub license, and/or sell copies of the Software, and to
11 * permit persons to whom the Software is furnished to do so, subject to
12 * the following conditions:
14 * The above copyright notice and this permission notice (including the
15 * next paragraph) shall be included in all copies or substantial portions
18 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
19 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
20 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT.
21 * IN NO EVENT SHALL TUNGSTEN GRAPHICS AND/OR ITS SUPPLIERS BE LIABLE FOR
22 * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
23 * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
24 * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
26 **************************************************************************/
31 #include "depthstencil.h"
33 #include "framebuffer.h"
36 #include "renderbuffer.h"
38 #include "intel_context.h"
39 #include "intel_fbo.h"
40 #include "intel_depthstencil.h"
41 #include "intel_regions.h"
45 * The GL_EXT_framebuffer_object allows the user to create their own
46 * framebuffer objects consisting of color renderbuffers (0 or more),
47 * depth renderbuffers (0 or 1) and stencil renderbuffers (0 or 1).
49 * The spec considers depth and stencil renderbuffers to be totally independent
50 * buffers. In reality, most graphics hardware today uses a combined
51 * depth+stencil buffer (one 32-bit pixel = 24 bits of Z + 8 bits of stencil).
53 * This causes difficulty because the user may create some number of depth
54 * renderbuffers and some number of stencil renderbuffers and bind them
55 * together in framebuffers in any combination.
57 * This code manages all that.
59 * 1. Depth renderbuffers are always allocated in hardware as 32bpp
60 * GL_DEPTH24_STENCIL8 buffers.
62 * 2. Stencil renderbuffers are initially allocated in software as 8bpp
63 * GL_STENCIL_INDEX8 buffers.
65 * 3. Depth and Stencil renderbuffers use the PairedStencil and PairedDepth
66 * fields (respectively) to indicate if the buffer's currently paired
67 * with another stencil or depth buffer (respectively).
69 * 4. When a depth and stencil buffer are initially both attached to the
70 * current framebuffer, we merge the stencil buffer values into the
71 * depth buffer (really a depth+stencil buffer). The then hardware uses
72 * the combined buffer.
74 * 5. Whenever a depth or stencil buffer is reallocated (with
75 * glRenderbufferStorage) we undo the pairing and copy the stencil values
76 * from the combined depth/stencil buffer back to the stencil-only buffer.
78 * 6. We also undo the pairing when we find a change in buffer bindings.
80 * 7. If a framebuffer is only using a depth renderbuffer (no stencil), we
81 * just use the combined depth/stencil buffer and ignore the stencil values.
83 * 8. If a framebuffer is only using a stencil renderbuffer (no depth) we have
84 * to promote the 8bpp software stencil buffer to a 32bpp hardware
85 * depth+stencil buffer.
92 map_regions(GLcontext
* ctx
,
93 struct intel_renderbuffer
*depthRb
,
94 struct intel_renderbuffer
*stencilRb
)
96 struct intel_context
*intel
= intel_context(ctx
);
97 if (depthRb
&& depthRb
->region
) {
98 intel_region_map(intel
, depthRb
->region
);
99 depthRb
->pfMap
= depthRb
->region
->map
;
100 depthRb
->pfPitch
= depthRb
->region
->pitch
;
102 if (stencilRb
&& stencilRb
->region
) {
103 intel_region_map(intel
, stencilRb
->region
);
104 stencilRb
->pfMap
= stencilRb
->region
->map
;
105 stencilRb
->pfPitch
= stencilRb
->region
->pitch
;
110 unmap_regions(GLcontext
* ctx
,
111 struct intel_renderbuffer
*depthRb
,
112 struct intel_renderbuffer
*stencilRb
)
114 struct intel_context
*intel
= intel_context(ctx
);
115 if (depthRb
&& depthRb
->region
) {
116 intel_region_unmap(intel
, depthRb
->region
);
117 depthRb
->pfMap
= NULL
;
118 depthRb
->pfPitch
= 0;
120 if (stencilRb
&& stencilRb
->region
) {
121 intel_region_unmap(intel
, stencilRb
->region
);
122 stencilRb
->pfMap
= NULL
;
123 stencilRb
->pfPitch
= 0;
130 * Undo the pairing/interleaving between depth and stencil buffers.
131 * irb should be a depth/stencil or stencil renderbuffer.
134 intel_unpair_depth_stencil(GLcontext
* ctx
, struct intel_renderbuffer
*irb
)
136 if (irb
->PairedStencil
) {
137 /* irb is a depth/stencil buffer */
138 struct gl_renderbuffer
*stencilRb
;
139 struct intel_renderbuffer
*stencilIrb
;
141 ASSERT(irb
->Base
._ActualFormat
== GL_DEPTH24_STENCIL8_EXT
);
143 stencilRb
= _mesa_lookup_renderbuffer(ctx
, irb
->PairedStencil
);
144 stencilIrb
= intel_renderbuffer(stencilRb
);
146 /* need to extract stencil values from the depth buffer */
147 ASSERT(stencilIrb
->PairedDepth
== irb
->Base
.Name
);
148 map_regions(ctx
, irb
, stencilIrb
);
149 _mesa_extract_stencil(ctx
, &irb
->Base
, &stencilIrb
->Base
);
150 unmap_regions(ctx
, irb
, stencilIrb
);
151 stencilIrb
->PairedDepth
= 0;
153 irb
->PairedStencil
= 0;
155 else if (irb
->PairedDepth
) {
156 /* irb is a stencil buffer */
157 struct gl_renderbuffer
*depthRb
;
158 struct intel_renderbuffer
*depthIrb
;
160 ASSERT(irb
->Base
._ActualFormat
== GL_STENCIL_INDEX8_EXT
||
161 irb
->Base
._ActualFormat
== GL_DEPTH24_STENCIL8_EXT
);
163 depthRb
= _mesa_lookup_renderbuffer(ctx
, irb
->PairedDepth
);
164 depthIrb
= intel_renderbuffer(depthRb
);
166 /* need to extract stencil values from the depth buffer */
167 ASSERT(depthIrb
->PairedStencil
== irb
->Base
.Name
);
168 map_regions(ctx
, depthIrb
, irb
);
169 _mesa_extract_stencil(ctx
, &depthIrb
->Base
, &irb
->Base
);
170 unmap_regions(ctx
, depthIrb
, irb
);
171 depthIrb
->PairedStencil
= 0;
173 irb
->PairedDepth
= 0;
176 _mesa_problem(ctx
, "Problem in undo_depth_stencil_pairing");
179 ASSERT(irb
->PairedStencil
== 0);
180 ASSERT(irb
->PairedDepth
== 0);
185 * Examine the depth and stencil renderbuffers which are attached to the
186 * framebuffer. If both depth and stencil are attached, make sure that the
187 * renderbuffers are 'paired' (combined). If only depth or only stencil is
188 * attached, undo any previous pairing.
190 * Must be called if NewState & _NEW_BUFFER (when renderbuffer attachments
191 * change, for example).
194 intel_validate_paired_depth_stencil(GLcontext
* ctx
,
195 struct gl_framebuffer
*fb
)
197 struct intel_renderbuffer
*depthRb
, *stencilRb
;
199 depthRb
= intel_get_renderbuffer(fb
, BUFFER_DEPTH
);
200 stencilRb
= intel_get_renderbuffer(fb
, BUFFER_STENCIL
);
202 if (depthRb
&& stencilRb
) {
203 if (depthRb
== stencilRb
) {
204 /* Using a user-created combined depth/stencil buffer.
207 ASSERT(depthRb
->Base
._BaseFormat
== GL_DEPTH_STENCIL_EXT
);
208 ASSERT(depthRb
->Base
._ActualFormat
== GL_DEPTH24_STENCIL8_EXT
);
211 /* Separate depth/stencil buffers, need to interleave now */
212 ASSERT(depthRb
->Base
._BaseFormat
== GL_DEPTH_COMPONENT
);
213 ASSERT(stencilRb
->Base
._BaseFormat
== GL_STENCIL_INDEX
);
214 /* may need to interleave depth/stencil now */
215 if (depthRb
->PairedStencil
== stencilRb
->Base
.Name
) {
216 /* OK, the depth and stencil buffers are already interleaved */
217 ASSERT(stencilRb
->PairedDepth
== depthRb
->Base
.Name
);
220 /* need to setup new pairing/interleaving */
221 if (depthRb
->PairedStencil
) {
222 intel_unpair_depth_stencil(ctx
, depthRb
);
224 if (stencilRb
->PairedDepth
) {
225 intel_unpair_depth_stencil(ctx
, stencilRb
);
228 ASSERT(depthRb
->Base
._ActualFormat
== GL_DEPTH24_STENCIL8_EXT
);
229 ASSERT(stencilRb
->Base
._ActualFormat
== GL_STENCIL_INDEX8_EXT
||
230 stencilRb
->Base
._ActualFormat
== GL_DEPTH24_STENCIL8_EXT
);
232 /* establish new pairing: interleave stencil into depth buffer */
233 map_regions(ctx
, depthRb
, stencilRb
);
234 _mesa_insert_stencil(ctx
, &depthRb
->Base
, &stencilRb
->Base
);
235 unmap_regions(ctx
, depthRb
, stencilRb
);
236 depthRb
->PairedStencil
= stencilRb
->Base
.Name
;
237 stencilRb
->PairedDepth
= depthRb
->Base
.Name
;
243 /* Depth buffer but no stencil buffer.
244 * We'll use a GL_DEPTH24_STENCIL8 buffer and ignore the stencil bits.
246 /* can't assert this until storage is allocated:
247 ASSERT(depthRb->Base._ActualFormat == GL_DEPTH24_STENCIL8_EXT);
249 /* intel_undo any previous pairing */
250 if (depthRb
->PairedStencil
) {
251 intel_unpair_depth_stencil(ctx
, depthRb
);
254 else if (stencilRb
) {
255 /* Stencil buffer but no depth buffer.
256 * Since h/w doesn't typically support just 8bpp stencil w/out Z,
257 * we'll use a GL_DEPTH24_STENCIL8 buffer and ignore the depth bits.
259 /* undo any previous pairing */
260 if (stencilRb
->PairedDepth
) {
261 intel_unpair_depth_stencil(ctx
, stencilRb
);
263 if (stencilRb
->Base
._ActualFormat
== GL_STENCIL_INDEX8_EXT
) {
264 /* promote buffer to GL_DEPTH24_STENCIL8 for hw rendering */
265 _mesa_promote_stencil(ctx
, &stencilRb
->Base
);
266 ASSERT(stencilRb
->Base
._ActualFormat
== GL_DEPTH24_STENCIL8_EXT
);
270 /* Finally, update the fb->_DepthBuffer and fb->_StencilBuffer fields */
271 _mesa_update_depth_buffer(ctx
, fb
, BUFFER_DEPTH
);
272 if (depthRb
&& depthRb
->PairedStencil
)
273 _mesa_update_stencil_buffer(ctx
, fb
, BUFFER_DEPTH
);
275 _mesa_update_stencil_buffer(ctx
, fb
, BUFFER_STENCIL
);
278 /* The hardware should use fb->Attachment[BUFFER_DEPTH].Renderbuffer
279 * first, if present, then fb->Attachment[BUFFER_STENCIL].Renderbuffer