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