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