]> gitweb.factorcode.org Git - factor.git/blob - extra/gpu/framebuffers/framebuffers.factor
1aa9ae33df895449eb409b1b51a1a3561908c427
[factor.git] / extra / gpu / framebuffers / framebuffers.factor
1 ! (c)2009 Joe Groff bsd license
2 USING: accessors alien.c-types arrays byte-arrays combinators
3 destructors gpu gpu.buffers gpu.private gpu.textures
4 gpu.textures.private images kernel locals math math.rectangles opengl
5 opengl.framebuffers opengl.gl opengl.textures sequences
6 specialized-arrays typed ui.gadgets.worlds variants ;
7 SPECIALIZED-ARRAY: int
8 SPECIALIZED-ARRAY: uint
9 IN: gpu.framebuffers
10
11 SINGLETON: system-framebuffer
12
13 TUPLE: renderbuffer < gpu-object
14     { component-order component-order initial: RGBA }
15     { component-type component-type initial: ubyte-components }
16     { samples integer initial: 0 } ;
17
18 <PRIVATE
19
20 : get-framebuffer-int ( enum -- value )
21     GL_RENDERBUFFER swap 0 <int> [ glGetRenderbufferParameteriv ] keep *int ;
22
23 PRIVATE>
24
25 TYPED:: allocate-renderbuffer ( renderbuffer: renderbuffer dim -- )
26     GL_RENDERBUFFER renderbuffer handle>> glBindRenderbuffer
27     GL_RENDERBUFFER
28     renderbuffer samples>> dup zero?
29     [ drop renderbuffer texture-gl-internal-format dim first2 glRenderbufferStorage ]
30     [ renderbuffer texture-gl-internal-format dim first2 glRenderbufferStorageMultisample ]
31     if ;
32
33 TYPED:: renderbuffer-dim ( renderbuffer: renderbuffer -- dim: array )
34     GL_RENDERBUFFER renderbuffer handle>> glBindRenderbuffer
35     GL_RENDERBUFFER_WIDTH get-framebuffer-int
36     GL_RENDERBUFFER_HEIGHT get-framebuffer-int 2array ;
37
38 TYPED: <renderbuffer> ( component-order: component-order
39                         component-type: component-type
40                         samples
41                         dim
42                         --
43                         renderbuffer )
44     [ [ gen-renderbuffer ] 3dip renderbuffer boa dup ] dip
45     [ allocate-renderbuffer ] [ drop ] if*
46     window-resource ;
47
48 M: renderbuffer dispose
49     [ [ delete-renderbuffer ] when* f ] change-handle drop ;
50
51 TUPLE: texture-1d-attachment
52     { texture texture-1d-data-target read-only initial: T{ texture-1d } }
53     { level integer read-only } ;
54
55 C: <texture-1d-attachment> texture-1d-attachment
56
57 TUPLE: texture-2d-attachment
58     { texture texture-2d-data-target read-only initial: T{ texture-2d } }
59     { level integer read-only } ;
60
61 C: <texture-2d-attachment> texture-2d-attachment
62
63 TUPLE: texture-3d-attachment
64     { texture texture-3d read-only initial: T{ texture-3d } }
65     { z-offset integer read-only }
66     { level integer read-only } ;
67
68 C: <texture-3d-attachment> texture-3d-attachment
69
70 TUPLE: texture-layer-attachment
71     { texture texture-3d-data-target read-only initial: T{ texture-3d } }
72     { layer integer read-only }
73     { level integer read-only } ;
74
75 C: <texture-layer-attachment> texture-layer-attachment
76
77 UNION: texture-attachment
78     texture-1d-attachment texture-2d-attachment texture-3d-attachment texture-layer-attachment ;
79
80 M: texture-attachment dispose texture>> dispose ;
81
82 UNION: framebuffer-attachment renderbuffer texture-attachment ;
83 UNION: ?framebuffer-attachment framebuffer-attachment POSTPONE: f ;
84
85 GENERIC: attachment-object ( attachment -- object )
86 M: renderbuffer attachment-object ;
87 M: texture-attachment attachment-object texture>> texture-object ;
88
89 TUPLE: framebuffer < gpu-object
90     { color-attachments array read-only }
91     { depth-attachment ?framebuffer-attachment read-only initial: f }
92     { stencil-attachment ?framebuffer-attachment read-only initial: f } ;
93
94 UNION: any-framebuffer system-framebuffer framebuffer ;
95
96 VARIANT: framebuffer-attachment-side
97     left-side right-side ;
98
99 VARIANT: framebuffer-attachment-face
100     back-face front-face ;
101
102 UNION: ?framebuffer-attachment-side framebuffer-attachment-side POSTPONE: f ;
103 UNION: ?framebuffer-attachment-face framebuffer-attachment-face POSTPONE: f ;
104
105 VARIANT: color-attachment-ref
106     default-attachment
107     system-attachment: {
108         { side ?framebuffer-attachment-side initial: f }
109         { face ?framebuffer-attachment-face initial: back-face }
110     }
111     color-attachment: { { index integer } } ;
112
113 VARIANT: non-color-attachment-ref
114     depth-attachment
115     stencil-attachment ;
116
117 UNION: attachment-ref
118     color-attachment-ref
119     non-color-attachment-ref
120     POSTPONE: f ;
121
122 TUPLE: framebuffer-rect
123     { framebuffer any-framebuffer read-only initial: system-framebuffer }
124     { attachment color-attachment-ref read-only initial: default-attachment }
125     { rect rect read-only } ;
126
127 C: <framebuffer-rect> framebuffer-rect
128
129 TYPED: framebuffer-attachment-at ( framebuffer: framebuffer
130                                    attachment-ref: attachment-ref
131                                    --
132                                    attachment: framebuffer-attachment )
133     {
134         { default-attachment [ color-attachments>> first ] }
135         { color-attachment [ swap color-attachments>> nth ] }
136         { depth-attachment [ depth-attachment>> ] }
137         { stencil-attachment [ stencil-attachment>> ] }
138     } match ;
139
140 <PRIVATE
141
142 GENERIC: framebuffer-handle ( framebuffer -- handle )
143
144 M: system-framebuffer framebuffer-handle drop 0 ;
145 M: framebuffer framebuffer-handle handle>> ;
146
147 GENERIC# allocate-framebuffer-attachment 1 ( framebuffer-attachment dim -- )
148
149 M: texture-attachment allocate-framebuffer-attachment
150     [ [ texture>> ] [ level>> ] bi ] dip f allocate-texture ;
151 M: renderbuffer allocate-framebuffer-attachment
152     allocate-renderbuffer ;
153
154 GENERIC: framebuffer-attachment-dim ( framebuffer-attachment -- dim )
155
156 M: texture-attachment framebuffer-attachment-dim
157     [ texture>> ] [ level>> ] bi texture-dim
158     dup number? [ 1 2array ] [ 2 head ] if ;
159
160 M: renderbuffer framebuffer-attachment-dim
161     renderbuffer-dim ;
162
163 : each-attachment ( framebuffer quot: ( attachment -- ) -- )
164     [ [ color-attachments>> ] dip each ]
165     [ swap depth-attachment>>   [ swap call ] [ drop ] if* ]
166     [ swap stencil-attachment>> [ swap call ] [ drop ] if* ] 2tri ; inline
167
168 :: each-attachment-target ( framebuffer quot: ( attachment-target attachment -- ) -- )
169     framebuffer color-attachments>>
170     [| attachment n | n GL_COLOR_ATTACHMENT0 + attachment quot call ] each-index
171     framebuffer depth-attachment>>
172     [| attachment | GL_DEPTH_ATTACHMENT attachment quot call ] when*
173     framebuffer stencil-attachment>>
174     [| attachment | GL_STENCIL_ATTACHMENT attachment quot call ] when* ; inline
175
176 GENERIC: bind-framebuffer-attachment ( attachment-target attachment -- )
177
178 M:: renderbuffer bind-framebuffer-attachment ( attachment-target renderbuffer -- )
179     GL_DRAW_FRAMEBUFFER attachment-target
180     GL_RENDERBUFFER renderbuffer handle>>
181     glFramebufferRenderbuffer ;
182
183 M:: texture-1d-attachment bind-framebuffer-attachment ( attachment-target texture-attachment -- )
184     GL_DRAW_FRAMEBUFFER attachment-target
185     texture-attachment [ texture>> [ texture-data-gl-target ] [ texture-object handle>> ] bi ] [ level>> ] bi
186     glFramebufferTexture1D ;
187
188 M:: texture-2d-attachment bind-framebuffer-attachment ( attachment-target texture-attachment -- )
189     GL_DRAW_FRAMEBUFFER attachment-target
190     texture-attachment [ texture>> [ texture-data-gl-target ] [ texture-object handle>> ] bi ] [ level>> ] bi
191     glFramebufferTexture2D ;
192
193 M:: texture-3d-attachment bind-framebuffer-attachment ( attachment-target texture-attachment -- )
194     GL_DRAW_FRAMEBUFFER attachment-target
195     texture-attachment
196     [ texture>> [ texture-data-gl-target ] [ texture-object handle>> ] bi ]
197     [ level>> ] [ z-offset>> ] tri
198     glFramebufferTexture3D ;
199
200 M:: texture-layer-attachment bind-framebuffer-attachment ( attachment-target texture-attachment -- )
201     GL_DRAW_FRAMEBUFFER attachment-target
202     texture-attachment
203     [ texture>> texture-object handle>> ]
204     [ level>> ] [ layer>> ] tri
205     glFramebufferTextureLayer ;
206
207 GENERIC: (default-gl-attachment) ( framebuffer -- gl-attachment )
208 GENERIC: (default-attachment-type) ( framebuffer -- type )
209 GENERIC: (default-attachment-image-type) ( framebuffer -- order type )
210
211 M: system-framebuffer (default-gl-attachment)
212     drop GL_BACK ;
213 M: framebuffer (default-gl-attachment)
214     drop GL_COLOR_ATTACHMENT0 ;
215
216 SYMBOLS: float-type int-type uint-type ;
217
218 : (color-attachment-type) ( framebuffer index -- type )
219     swap color-attachments>> nth attachment-object component-type>> {
220         { [ dup signed-unnormalized-integer-components?   ] [ drop int-type  ] }
221         { [ dup unsigned-unnormalized-integer-components? ] [ drop uint-type ] }
222         [ drop float-type ]
223     } cond ;
224
225 M: system-framebuffer (default-attachment-type)
226     drop float-type ;
227 M: framebuffer (default-attachment-type)
228     0 (color-attachment-type) ;
229
230 M: system-framebuffer (default-attachment-image-type) ( framebuffer -- order type )
231     drop RGBA ubyte-components ;
232 M: framebuffer (default-attachment-image-type) ( framebuffer -- order type )
233     color-attachments>> first attachment-object
234     [ component-order>> ] [ component-type>> ] bi ;
235
236 : gl-system-attachment ( side face -- attachment )
237     2array {
238         { { f          f          } [ GL_FRONT_AND_BACK ] }
239         { { f          front-face } [ GL_FRONT          ] }
240         { { f          back-face  } [ GL_BACK           ] }
241         { { left-side  f          } [ GL_LEFT           ] }
242         { { left-side  front-face } [ GL_FRONT_LEFT     ] }
243         { { left-side  back-face  } [ GL_BACK_LEFT      ] }
244         { { right-side f          } [ GL_RIGHT          ] }
245         { { right-side front-face } [ GL_FRONT_RIGHT    ] }
246         { { right-side back-face  } [ GL_BACK_RIGHT     ] }
247     } case ;
248
249 : gl-attachment ( framebuffer attachment-ref -- gl-attachment )
250     [ {
251         { depth-attachment [ GL_DEPTH_ATTACHMENT ] }
252         { stencil-attachment [ GL_STENCIL_ATTACHMENT ] }
253         { color-attachment [ GL_COLOR_ATTACHMENT0 + ] }
254         { system-attachment [ gl-system-attachment ] }
255         { default-attachment [ dup (default-gl-attachment) ] }
256     } match ] [ GL_NONE ] if* nip ;
257
258 : color-attachment-image-type ( framebuffer attachment-ref -- order type )
259     {
260         { color-attachment [
261             swap color-attachments>> nth
262             attachment-object [ component-order>> ] [ component-type>> ] bi
263         ] }
264         { system-attachment [ 3drop RGBA ubyte-components ] }
265         { default-attachment [ (default-attachment-image-type) ] }
266     } match ;
267
268 : framebuffer-rect-image-type ( framebuffer-rect -- order type )
269     [ framebuffer>> ] [ attachment>> ] bi color-attachment-image-type ;
270
271 HOOK: (clear-integer-color-attachment) gpu-api ( type value -- )
272
273 M: opengl-2 (clear-integer-color-attachment)
274     4 0 pad-tail first4
275     swap {
276         { int-type [ glClearColorIiEXT ] }
277         { uint-type [ glClearColorIuiEXT ] }
278     } case GL_COLOR_BUFFER_BIT glClear ;
279
280 M: opengl-3 (clear-integer-color-attachment)
281     [ GL_COLOR 0 ] dip 4 0 pad-tail
282     swap {
283         { int-type  [ >int-array  glClearBufferiv  ] }
284         { uint-type [ >uint-array glClearBufferuiv ] }
285     } case ;
286
287 :: (clear-color-attachment) ( type attachment value -- )
288     attachment glDrawBuffer
289     type float-type =
290     [ value 4 value last pad-tail first4 glClearColor GL_COLOR_BUFFER_BIT glClear ]
291     [ type value (clear-integer-color-attachment) ] if ;
292
293 : framebuffer-rect-size ( framebuffer-rect -- size )
294     [ rect>> dim>> product ]
295     [ framebuffer-rect-image-type (bytes-per-pixel) ] bi * ;
296
297 PRIVATE>
298
299 TYPED: <full-framebuffer-rect> ( framebuffer: any-framebuffer
300                                  attachment: attachment-ref
301                                  --
302                                  framebuffer-rect: framebuffer-rect )
303     2dup framebuffer-attachment-at
304     { 0 0 } swap framebuffer-attachment-dim <rect>
305     <framebuffer-rect> ;
306
307 TYPED: resize-framebuffer ( framebuffer: framebuffer dim -- )
308     [ allocate-framebuffer-attachment ] curry each-attachment ;
309
310 :: attach-framebuffer-attachments ( framebuffer -- )
311     GL_DRAW_FRAMEBUFFER framebuffer handle>> glBindFramebuffer
312     framebuffer [ bind-framebuffer-attachment ] each-attachment-target ; inline
313
314 M: framebuffer dispose
315     [ [ delete-framebuffer ] when* f ] change-handle drop ;
316
317 TYPED: dispose-framebuffer-attachments ( framebuffer: framebuffer -- )
318     [ [ dispose ] when* ] each-attachment ;
319
320 : <framebuffer> ( color-attachments
321                   depth-attachment: framebuffer-attachment
322                   stencil-attachment: framebuffer-attachment
323                   dim
324                   --
325                   framebuffer: framebuffer )
326     [ [ 0 ] 3dip framebuffer boa dup ] dip
327     [ resize-framebuffer ] [ drop ] if*
328     gen-framebuffer >>handle
329     dup attach-framebuffer-attachments
330     window-resource ;
331
332 TYPED:: clear-framebuffer-attachment ( framebuffer: any-framebuffer
333                                        attachment-ref: attachment-ref
334                                        value -- )
335     GL_DRAW_FRAMEBUFFER framebuffer framebuffer-handle glBindFramebuffer
336     attachment-ref {
337         { system-attachment [| side face |
338             float-type
339             side face gl-system-attachment
340             value (clear-color-attachment)
341         ] }
342         { color-attachment [| i |
343             framebuffer i (color-attachment-type)
344             GL_COLOR_ATTACHMENT0 i +
345             value (clear-color-attachment)
346         ] }
347         { default-attachment [
348             framebuffer [ (default-attachment-type) ] [ (default-gl-attachment) ] bi
349             value (clear-color-attachment)
350         ] }
351         { depth-attachment   [ value glClearDepth GL_DEPTH_BUFFER_BIT glClear ] }
352         { stencil-attachment [ value glClearStencil GL_STENCIL_BUFFER_BIT glClear ] }
353     } match ;
354
355 : clear-framebuffer ( framebuffer alist -- )
356     [ first2 clear-framebuffer-attachment ] with each ; inline
357
358 TYPED:: read-framebuffer-to ( framebuffer-rect: framebuffer-rect
359                               gpu-data-ptr -- )
360     GL_READ_FRAMEBUFFER framebuffer-rect framebuffer>> framebuffer-handle glBindFramebuffer
361     framebuffer-rect [ framebuffer>> ] [ attachment>> ] bi gl-attachment glReadBuffer
362     framebuffer-rect rect>> [ loc>> first2 ] [ dim>> first2 ] bi 
363     framebuffer-rect framebuffer-rect-image-type image-data-format
364     gpu-data-ptr pixel-pack-buffer [ glReadPixels ] with-gpu-data-ptr ;
365     
366 : read-framebuffer ( framebuffer-rect -- byte-array )
367     dup framebuffer-rect-size <byte-array> [ read-framebuffer-to ] keep ; inline
368
369 TYPED: read-framebuffer-image ( framebuffer-rect -- image )
370     [ <image> ] dip {
371         [ rect>> dim>> >>dim ]
372         [
373             framebuffer-rect-image-type
374             [ >>component-order ] [ >>component-type ] bi*
375         ]
376         [ read-framebuffer >>bitmap ] 
377     } cleave ;
378
379 TYPED:: copy-framebuffer ( to-fb-rect: framebuffer-rect
380                            from-fb-rect: framebuffer-rect
381                            depth? stencil? filter: texture-filter -- )
382     GL_DRAW_FRAMEBUFFER to-fb-rect framebuffer>> framebuffer-handle glBindFramebuffer
383     to-fb-rect [ framebuffer>> ] [ attachment>> ] bi gl-attachment glDrawBuffer
384     GL_READ_FRAMEBUFFER from-fb-rect framebuffer>> framebuffer-handle glBindFramebuffer
385     from-fb-rect [ framebuffer>> ] [ attachment>> ] bi gl-attachment glReadBuffer
386     to-fb-rect attachment>> [ GL_COLOR_BUFFER_BIT ] [ 0 ] if
387     depth?   [ GL_DEPTH_BUFFER_BIT   ] [ 0 ] if bitor
388     stencil? [ GL_STENCIL_BUFFER_BIT ] [ 0 ] if bitor :> mask
389     
390     from-fb-rect rect>> rect-extent [ first2 ] bi@
391     to-fb-rect   rect>> rect-extent [ first2 ] bi@
392     mask filter gl-mag-filter glBlitFramebuffer ;
393