summaryrefslogtreecommitdiff
blob: 59b2d275ddaf39c4d0535585209a157bf6a512bb (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
From 2b5eb9205ae85c8b459d993da803a31c847e5776 Mon Sep 17 00:00:00 2001
From: Neil Roberts <neil@linux.intel.com>
Date: Thu, 11 Nov 2010 15:28:44 +0000
Subject: [PATCH] Add an internal _cogl_offscreen_new_to_texture_full function

This function is the same as cogl_offscreen_new_to_texture but it
takes a level parameter and a set of flags so that FBOs can be used to
render to higher mipmap levels and to disable the depth and stencil
buffers. cogl_offscreen_new_to_texture now just calls the new function
with the level set to zero. This function could be useful in a few
places in Cogl where we want to use FBOs as an implementation detail
such as when copying between textures.

http://bugzilla.clutter-project.org/show_bug.cgi?id=2414
---
 clutter/cogl/cogl/cogl-framebuffer-private.h |   24 ++++++
 clutter/cogl/cogl/cogl-framebuffer.c         |  100 +++++++++++++++++++------
 2 files changed, 100 insertions(+), 24 deletions(-)

diff --git a/clutter/cogl/cogl/cogl-framebuffer-private.h b/clutter/cogl/cogl/cogl-framebuffer-private.h
index 1ae102e..803befd 100644
--- a/clutter/cogl/cogl/cogl-framebuffer-private.h
+++ b/clutter/cogl/cogl/cogl-framebuffer-private.h
@@ -66,6 +66,12 @@ typedef struct _CoglOffscreen
   CoglHandle      texture;
 } CoglOffscreen;
 
+/* Flags to pass to _cogl_offscreen_new_to_texture_full */
+typedef enum
+{
+  COGL_OFFSCREEN_DISABLE_DEPTH_STENCIL = 1
+} CoglOffscreenFlags;
+
 #define COGL_OFFSCREEN(X) ((CoglOffscreen *)(X))
 
 typedef struct _CoglOnscreen
@@ -143,5 +149,23 @@ _cogl_create_framebuffer_stack (void);
 void
 _cogl_free_framebuffer_stack (GSList *stack);
 
+/*
+ * _cogl_offscreen_new_to_texture_full:
+ * @texhandle: A handle to the texture to target
+ * @create_flags: Flags specifying how to create the FBO
+ * @level: The mipmap level within the texture to target
+ *
+ * Creates a new offscreen buffer which will target the given
+ * texture. By default the buffer will have a depth and stencil
+ * buffer. This can be disabled by passing
+ * %COGL_OFFSCREEN_DISABLE_DEPTH_STENCIL in @create_flags.
+ *
+ * Return value: the new CoglOffscreen object.
+ */
+CoglHandle
+_cogl_offscreen_new_to_texture_full (CoglHandle texhandle,
+                                     CoglOffscreenFlags create_flags,
+                                     unsigned int level);
+
 #endif /* __COGL_FRAMEBUFFER_PRIVATE_H */
 
diff --git a/clutter/cogl/cogl/cogl-framebuffer.c b/clutter/cogl/cogl/cogl-framebuffer.c
index 2042c0a..5e832b1 100644
--- a/clutter/cogl/cogl/cogl-framebuffer.c
+++ b/clutter/cogl/cogl/cogl-framebuffer.c
@@ -324,10 +324,18 @@ _cogl_framebuffer_init_bits (CoglFramebuffer *framebuffer)
   framebuffer->dirty_bitmasks = FALSE;
 }
 
+typedef struct
+{
+  CoglHandle texture;
+  unsigned int level;
+  unsigned int level_width;
+  unsigned int level_height;
+} CoglFramebufferTryFBOData;
+
 static gboolean
 try_creating_fbo (CoglOffscreen *offscreen,
                   TryFBOFlags flags,
-                  CoglHandle texture)
+                  CoglFramebufferTryFBOData *data)
 {
   GLuint gl_depth_stencil_handle;
   GLuint gl_depth_handle;
@@ -339,7 +347,8 @@ try_creating_fbo (CoglOffscreen *offscreen,
 
   _COGL_GET_CONTEXT (ctx, FALSE);
 
-  if (!cogl_texture_get_gl_texture (texture, &tex_gl_handle, &tex_gl_target))
+  if (!cogl_texture_get_gl_texture (data->texture,
+                                    &tex_gl_handle, &tex_gl_target))
     return FALSE;
 
   if (tex_gl_target != GL_TEXTURE_2D
@@ -362,7 +371,7 @@ try_creating_fbo (CoglOffscreen *offscreen,
   offscreen->fbo_handle = fbo_gl_handle;
 
   GE (glFramebufferTexture2D (GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0,
-			      tex_gl_target, tex_gl_handle, 0));
+                              tex_gl_target, tex_gl_handle, data->level));
 
   if (flags & _TRY_DEPTH_STENCIL)
     {
@@ -370,8 +379,8 @@ try_creating_fbo (CoglOffscreen *offscreen,
       GE (glGenRenderbuffers (1, &gl_depth_stencil_handle));
       GE (glBindRenderbuffer (GL_RENDERBUFFER, gl_depth_stencil_handle));
       GE (glRenderbufferStorage (GL_RENDERBUFFER, GL_DEPTH_STENCIL,
-                                 cogl_texture_get_width (texture),
-                                 cogl_texture_get_height (texture)));
+                                 data->level_width,
+                                 data->level_height));
       GE (glBindRenderbuffer (GL_RENDERBUFFER, 0));
       GE (glFramebufferRenderbuffer (GL_FRAMEBUFFER,
                                      GL_STENCIL_ATTACHMENT,
@@ -391,8 +400,8 @@ try_creating_fbo (CoglOffscreen *offscreen,
       /* For now we just ask for GL_DEPTH_COMPONENT16 since this is all that's
        * available under GLES */
       GE (glRenderbufferStorage (GL_RENDERBUFFER, GL_DEPTH_COMPONENT16,
-                                 cogl_texture_get_width (texture),
-                                 cogl_texture_get_height (texture)));
+                                 data->level_width,
+                                 data->level_height));
       GE (glBindRenderbuffer (GL_RENDERBUFFER, 0));
       GE (glFramebufferRenderbuffer (GL_FRAMEBUFFER,
                                      GL_DEPTH_ATTACHMENT,
@@ -407,8 +416,8 @@ try_creating_fbo (CoglOffscreen *offscreen,
       GE (glGenRenderbuffers (1, &gl_stencil_handle));
       GE (glBindRenderbuffer (GL_RENDERBUFFER, gl_stencil_handle));
       GE (glRenderbufferStorage (GL_RENDERBUFFER, GL_STENCIL_INDEX8,
-                                 cogl_texture_get_width (texture),
-                                 cogl_texture_get_height (texture)));
+                                 data->level_width,
+                                 data->level_height));
       GE (glBindRenderbuffer (GL_RENDERBUFFER, 0));
       GE (glFramebufferRenderbuffer (GL_FRAMEBUFFER,
                                      GL_STENCIL_ATTACHMENT,
@@ -443,11 +452,16 @@ try_creating_fbo (CoglOffscreen *offscreen,
 }
 
 CoglHandle
-cogl_offscreen_new_to_texture (CoglHandle texhandle)
+_cogl_offscreen_new_to_texture_full (CoglHandle texhandle,
+                                     CoglOffscreenFlags create_flags,
+                                     unsigned int level)
 {
   CoglOffscreen      *offscreen;
   static TryFBOFlags  flags;
   static gboolean     have_working_flags = FALSE;
+  unsigned int        i;
+  CoglFramebufferTryFBOData data;
+  gboolean            fbo_created;
 
   _COGL_GET_CONTEXT (ctx, COGL_INVALID_HANDLE);
 
@@ -462,6 +476,27 @@ cogl_offscreen_new_to_texture (CoglHandle texhandle)
   if (cogl_texture_is_sliced (texhandle))
     return COGL_INVALID_HANDLE;
 
+  data.texture = texhandle;
+  data.level = level;
+
+  /* Calculate the size of the texture at this mipmap level to ensure
+     that it's a valid level */
+  data.level_width = cogl_texture_get_width (texhandle);
+  data.level_height = cogl_texture_get_height (texhandle);
+
+  for (i = 0; i < level; i++)
+    {
+      /* If neither dimension can be further divided then the level is
+         invalid */
+      if (data.level_width == 1 && data.level_height == 1)
+        return COGL_INVALID_HANDLE;
+
+      if (data.level_width > 1)
+        data.level_width >>= 1;
+      if (data.level_height > 1)
+        data.level_height >>= 1;
+    }
+
   /* XXX: The framebuffer_object spec isn't clear in defining whether attaching
    * a texture as a renderbuffer with mipmap filtering enabled while the
    * mipmaps have not been uploaded should result in an incomplete framebuffer
@@ -477,25 +512,36 @@ cogl_offscreen_new_to_texture (CoglHandle texhandle)
   offscreen = g_new0 (CoglOffscreen, 1);
   offscreen->texture = cogl_handle_ref (texhandle);
 
-  if ((have_working_flags &&
-       try_creating_fbo (offscreen, flags, texhandle)) ||
+  if ((create_flags & COGL_OFFSCREEN_DISABLE_DEPTH_STENCIL))
+    fbo_created = try_creating_fbo (offscreen, flags = 0, &data);
+  else
+    {
+      if ((have_working_flags &&
+           try_creating_fbo (offscreen, flags, &data)) ||
 #ifdef HAVE_COGL_GL
-      try_creating_fbo (offscreen, flags = _TRY_DEPTH_STENCIL, texhandle) ||
+          try_creating_fbo (offscreen, flags = _TRY_DEPTH_STENCIL, &data) ||
 #endif
-      try_creating_fbo (offscreen, flags = _TRY_DEPTH | _TRY_STENCIL,
-                        texhandle) ||
-      try_creating_fbo (offscreen, flags = _TRY_STENCIL, texhandle) ||
-      try_creating_fbo (offscreen, flags = _TRY_DEPTH, texhandle) ||
-      try_creating_fbo (offscreen, flags = 0, texhandle))
-    {
-      /* Record that the last set of flags succeeded so that we can
-         try that set first next time */
-      have_working_flags = TRUE;
+          try_creating_fbo (offscreen, flags = _TRY_DEPTH | _TRY_STENCIL,
+                            &data) ||
+          try_creating_fbo (offscreen, flags = _TRY_STENCIL, &data) ||
+          try_creating_fbo (offscreen, flags = _TRY_DEPTH, &data) ||
+          try_creating_fbo (offscreen, flags = 0, &data))
+        {
+          /* Record that the last set of flags succeeded so that we can
+             try that set first next time */
+          have_working_flags = TRUE;
+          fbo_created = TRUE;
+        }
+      else
+        fbo_created = FALSE;
+    }
 
+  if (fbo_created)
+    {
       _cogl_framebuffer_init (COGL_FRAMEBUFFER (offscreen),
                               COGL_FRAMEBUFFER_TYPE_OFFSCREEN,
-                              cogl_texture_get_width (texhandle),
-                              cogl_texture_get_height (texhandle));
+                              data.level_width,
+                              data.level_height);
 
       return _cogl_offscreen_object_new (offscreen);
     }
@@ -508,6 +554,12 @@ cogl_offscreen_new_to_texture (CoglHandle texhandle)
     }
 }
 
+CoglHandle
+cogl_offscreen_new_to_texture (CoglHandle texhandle)
+{
+  return _cogl_offscreen_new_to_texture_full (texhandle, 0, 0);
+}
+
 static void
 _cogl_offscreen_free (CoglOffscreen *offscreen)
 {
-- 
1.7.3.16.g9464b