From b5aa7cb9a857160e547718d184e89cb3221200a5 Mon Sep 17 00:00:00 2001 From: David Thompson Date: Sat, 19 Oct 2024 21:05:41 -0400 Subject: WIP path stuff --- chickadee.scm | 22 ++-- chickadee/graphics.scm | 42 +++++--- chickadee/graphics/backend.scm | 17 +-- chickadee/graphics/backend/opengl.scm | 195 +++++++++++++++++++++------------- examples/path.scm | 2 + 5 files changed, 178 insertions(+), 100 deletions(-) diff --git a/chickadee.scm b/chickadee.scm index 0654ea3..f726691 100644 --- a/chickadee.scm +++ b/chickadee.scm @@ -162,6 +162,7 @@ not being pushed at all." (define default-color-texture-view (make-parameter #f)) (define default-depth+stencil-texture-view (make-parameter #f)) +(define default-resolve-target (make-parameter #f)) (define* (make-window #:key (title "Chickadee") fullscreen? resizable? (width 640) (height 480)) @@ -303,6 +304,7 @@ border is disabled, otherwise it is enabled.") (vector (make-color-attachment #:view default-color-texture-view + #:resolve-target default-resolve-target #:operation (make-color-operation #:clear-color db32-viking))) #:depth+stencil-attachment @@ -417,7 +419,7 @@ border is disabled, otherwise it is enabled.") (current-projection default-projection) (current-pass default-render-pass)) (draw alpha)) - ((@@ (chickadee graphics) end-frame) (default-color-texture-view))) + ((@@ (chickadee graphics) end-frame) (default-resolve-target))) (define (on-error e stack) (error e stack) ;; Flush all input events that have occurred while in the error @@ -426,9 +428,11 @@ border is disabled, otherwise it is enabled.") (define (refresh-default-texture-views! width height) (let* ((old-color (default-color-texture-view)) (old-depth+stencil (default-depth+stencil-texture-view)) + (old-resolve-target (default-resolve-target)) (color-texture (make-texture #:name "Default color texture" #:width width - #:height height)) + #:height height + #:samples 4)) (color-view (make-texture-view color-texture #:name "Default color texture view")) (depth+stencil-texture (make-texture #:name "Default depth/stencil texture" @@ -436,11 +440,19 @@ border is disabled, otherwise it is enabled.") #:height height #:format 'depth24plus-stencil8)) (depth+stencil-view (make-texture-view depth+stencil-texture - #:name "Default depth/stencil texture view"))) + #:name "Default depth/stencil texture view")) + (resolve-target-texture (make-texture #:name "Default resolve target texture" + #:width width + #:height height)) + (resolve-target (make-texture-view resolve-target-texture + #:name "Default resolve target texture view"))) + ;; TODO: Destroy the underlying textures, too? (when old-color (destroy-texture-view old-color)) (when old-depth+stencil (destroy-texture-view old-depth+stencil)) + (when old-resolve-target (destroy-texture-view old-resolve-target)) (default-color-texture-view color-view) - (default-depth+stencil-texture-view depth+stencil-view))) + (default-depth+stencil-texture-view depth+stencil-view) + (default-resolve-target resolve-target))) (parameterize ((current-window window) (gpu:current-gpu gpu)) (refresh-default-texture-views! window-width window-height) @@ -452,8 +464,6 @@ border is disabled, otherwise it is enabled.") (lambda args (display "warning: could not enable vsync\n" (current-error-port)))) - ;; Turn off multisampling by default. - ;; (gl-disable (version-1-3 multisample)) ;; Enable seamless cube maps. ;; (gl-enable (version-3-2 texture-cube-map-seamless)) (sdl2:load-game-controller-mappings! diff --git a/chickadee/graphics.scm b/chickadee/graphics.scm index 26c8515..80f26fa 100644 --- a/chickadee/graphics.scm +++ b/chickadee/graphics.scm @@ -93,17 +93,24 @@ (gpu:begin-frame (gpu:current-gpu))) (define (end-frame view) - (end-stream) - (gpu:end-frame (gpu:current-gpu) (texture-view-handle view))) + (let* ((gpu (gpu:current-gpu)) + (pass-box (graphics-variable-ref last-pass)) + (pass (unbox pass-box))) + (when pass + (end-render-pass pass) + (set-box! pass-box #f)) + (end-stream) + (gpu:end-frame (gpu:current-gpu) (texture-view-handle view)))) + +(define (resolve-texture-view view) + (match view + (#f #f) + ((? texture-view?) + (texture-view-handle view)) + ((? procedure?) + (texture-view-handle (view))))) (define (begin-render-pass pass) - (define (resolve-texture-view view) - (match view - (#f #f) - ((? texture-view?) - (texture-view-handle view)) - ((? procedure?) - (texture-view-handle (view))))) (match pass (($ colors depth+stencil) (let* ((gpu (gpu:current-gpu)) @@ -126,10 +133,19 @@ (gpu:submit gpu cmd))))) (define (end-render-pass pass) - (let* ((gpu (gpu:current-gpu)) - (cmd (gpu:request-end-render-pass-command gpu))) - (gpu:set-end-render-pass-command-pass! cmd pass) - (gpu:submit gpu cmd))) + (pk 'end-render-pass) + (match pass + (($ colors) + (let* ((gpu (gpu:current-gpu)) + (cmd (gpu:request-end-render-pass-command gpu))) + (do ((i 0 (+ i 1))) + ((= i (vector-length colors))) + (match (vector-ref colors i) + (($ view resolve-target op) + (let ((view (resolve-texture-view view)) + (resolve-target (resolve-texture-view resolve-target))) + (gpu:end-render-pass-command-resolve-target-set! cmd i resolve-target))))) + (gpu:submit gpu cmd))))) (define (draw* start count instances pipeline pass viewport scissor blend-constant stencil-reference index-buffer vertex-buffers diff --git a/chickadee/graphics/backend.scm b/chickadee/graphics/backend.scm index e08fdb0..91b5645 100644 --- a/chickadee/graphics/backend.scm +++ b/chickadee/graphics/backend.scm @@ -58,8 +58,7 @@ end-render-pass-command? - end-render-pass-command-pass - set-end-render-pass-command-pass! + end-render-pass-command-resolve-target-set! make-gpu-limits gpu-limits? @@ -151,12 +150,15 @@ (vector-set! v 2 stencil-op))) (define-record-type - (make-end-render-pass-command) + (make-end-render-pass-command resolve-targets) end-render-pass-command? - (pass end-render-pass-command-pass set-end-render-pass-command-pass!)) + (resolve-targets end-render-pass-command-resolve-targets)) -(define (fresh-end-render-pass-command) - (make-end-render-pass-command)) +(define (end-render-pass-command-resolve-target-set! cmd i resolve-target) + (vector-set! (end-render-pass-command-resolve-targets cmd) i resolve-target)) + +(define (fresh-end-render-pass-command max-color-attachments) + (make-end-render-pass-command (make-vector max-color-attachments #f))) (define-record-type (make-draw-command start count vertex-buffers bindings) @@ -429,7 +431,8 @@ (gpu-limits-max-color-attachments (gpu-limits gpu)))) (define (request-end-render-pass-command gpu) - (fresh-end-render-pass-command)) + (fresh-end-render-pass-command + (gpu-limits-max-color-attachments (gpu-limits gpu)))) (define (request-draw-command gpu) (pool-borrow (gpu-draw-command-pool gpu))) diff --git a/chickadee/graphics/backend/opengl.scm b/chickadee/graphics/backend/opengl.scm index c1753f3..25e028a 100644 --- a/chickadee/graphics/backend/opengl.scm +++ b/chickadee/graphics/backend/opengl.scm @@ -354,6 +354,19 @@ object.") -> void) "Attach a renderbuffer object to a framebuffer object.") +(define-gl-procedure (glBlitFramebuffer (src-x0 GLint) + (src-y0 GLint) + (src-x1 GLint) + (src-y1 GLint) + (dst-x0 GLint) + (dst-y0 GLint) + (dst-x1 GLint) + (dst-y1 GLint) + (mask GLbitfield) + (filter GLenum) + -> void) + "Copy a block of pixels from one framebuffer object to another.") + (define-gl-procedure (glUniform1ui (location GLint) (v0 GLuint) -> void) @@ -397,6 +410,7 @@ object.") (define gl-bind-renderbuffer glBindRenderbuffer) (define gl-renderbuffer-storage glRenderbufferStorage) (define gl-framebuffer-renderbuffer glFramebufferRenderbuffer) +(define gl-blit-framebuffer glBlitFramebuffer) (define gl-uniform1ui glUniform1ui) (define gl-uniform1uiv glUniform1uiv) @@ -597,6 +611,7 @@ object.") texture-views-supported? samplers-supported? uniform-buffers-supported? + framebuffer-blit-supported? blending? face-culling? depth-test? @@ -631,8 +646,7 @@ object.") shader draw-framebuffer read-framebuffer - mode - framebuffer-cache) + mode) gl-state? (gl-context gl-state-gl-context) (swap gl-state-swap) @@ -648,6 +662,7 @@ object.") (texture-views-supported? gl-state-texture-views-supported?) (samplers-supported? gl-state-samplers-supported?) (uniform-buffers-supported? gl-state-uniform-buffers-supported?) + (framebuffer-blit-supported? gl-state-framebuffer-blit-supported?) ;; Capability flags (blending? gl-state-blending? %set-gl-state-blending!) (face-culling? gl-state-face-culling? %set-gl-state-face-culling!) @@ -689,7 +704,11 @@ object.") ;; Command state (mode gl-state-mode set-gl-state-mode!) ; default, render-pass, etc. ;; Render pass state - (framebuffer-cache gl-state-framebuffer-cache) + (render-pass-draw-framebuffer gl-state-render-pass-draw-framebuffer + set-gl-state-render-pass-draw-framebuffer!) + (render-pass-resolve-framebuffer gl-state-render-pass-resolve-framebuffer + set-gl-state-render-pass-resolve-framebuffer!) + ;; (framebuffer-cache gl-state-framebuffer-cache) ;; State for drawing to default framebuffer (screen-indices gl-state-screen-indices set-gl-state-screen-indices!) (screen-vertices gl-state-screen-vertices set-gl-state-screen-vertices!) @@ -1070,7 +1089,7 @@ object.") (target (match dimension ('1d (texture-target texture-1d)) ('2d (if multisample? - (version-3-2 texture-2d-multisample) + (arb-texture-multisample texture-2d-multisample) (texture-target texture-2d))) ('3d (texture-target texture-3d-ext)))) (format (lower-texture-format format)) @@ -1156,7 +1175,11 @@ object.") mip-levels base-layer layers) (let ((target (match dimension ('1d (texture-target texture-1d)) - ('2d (texture-target texture-2d)) + ('2d + (if (eq? (gl-texture-target texture) + (arb-texture-multisample texture-2d-multisample)) + (arb-texture-multisample texture-2d-multisample) + (texture-target texture-2d))) ('2d-array (version-3-0 texture-2d-array)) ('cube (version-1-3 texture-cube-map)) ('cube-array (arb-texture-cube-map-array texture-cube-map-array)) @@ -1448,13 +1471,13 @@ object.") (define (set-gl-state-draw-framebuffer! state fbo) (unless (eq? (gl-state-draw-framebuffer state) fbo) - (gl-bind-framebuffer (version-3-0 framebuffer) + (gl-bind-framebuffer (version-3-0 draw-framebuffer) (gl-framebuffer-id fbo)) (%set-gl-state-draw-framebuffer! state fbo))) (define (set-gl-state-read-framebuffer! state fbo) (unless (eq? (gl-state-read-framebuffer state) fbo) - (gl-bind-framebuffer (version-3-0 framebuffer) + (gl-bind-framebuffer (version-3-0 read-framebuffer) (gl-framebuffer-id fbo)) (%set-gl-state-read-framebuffer! state fbo))) @@ -1472,39 +1495,6 @@ object.") (gl-delete-framebuffer (gl-framebuffer-id fbo)) (set-gl-framebuffer-destroyed! fbo #t))) -(define (gl-state-framebuffer-ref state key) - (hashq-ref (gl-state-framebuffer-cache state) key)) - -;; Find or create framebuffer and update attachments. -(define (gl-state-framebuffer-build state key colors depth+stencil) - (let* ((fbo-cache (gl-state-framebuffer-cache state)) - (fbo (or (hashq-ref fbo-cache key) - (let ((new (make-gl-framebuffer state))) - (hashq-set! fbo-cache key new) - new)))) - (set-gl-state-draw-framebuffer! state fbo) - (do ((i 0 (+ i 1))) - ((= i (vector-length colors))) - (match (vector-ref colors i) - (#(#f _ _) - (gl-framebuffer-texture-2d (version-3-0 framebuffer) - (+ (version-3-0 color-attachment0) i) - (texture-target texture-2d) 0 0)) - (#(($ id target) _ _) - (gl-framebuffer-texture-2d (version-3-0 framebuffer) - (+ (version-3-0 color-attachment0) i) - target id 0)))) - (match depth+stencil - (#(#f _ _) - (gl-framebuffer-texture-2d (version-3-0 framebuffer) - (arb-framebuffer-object depth-stencil-attachment) - (texture-target texture-2d) 0 0)) - (#(($ id target) _ _) - (gl-framebuffer-texture-2d (version-3-0 framebuffer) - (arb-framebuffer-object depth-stencil-attachment) - target id 0))) - fbo)) - ;;; ;;; Render pipelines @@ -1716,11 +1706,7 @@ object.") (make-gl-stencil-op (stencil-op* fail-back) (stencil-op* depth-fail-back) (stencil-op* pass-back))))) - (match multisample - (#f #f) - ;; TODO: Figure out what to do with multisample settings. - (($ count mask alpha-to-coverage?) - #f)) + multisample vertex-attributes binding-layout)) @@ -1734,7 +1720,9 @@ object.") ;;; (define (gl-state-init! state) - (let* ((verts (f32vector -1.0 -1.0 0.0 0.0 + (let* ((draw-framebuffer (make-gl-framebuffer state)) + (resolve-framebuffer (make-gl-framebuffer state)) + (verts (f32vector -1.0 -1.0 0.0 0.0 +1.0 -1.0 1.0 0.0 +1.0 +1.0 1.0 1.0 -1.0 +1.0 0.0 1.0)) @@ -1789,7 +1777,9 @@ void main (void) { (write-gl-buffer state indices 0 is 0 ilength) (set-gl-state-screen-vertices! state vertices) (set-gl-state-screen-indices! state indices) - (set-gl-state-screen-shader! state shader))) + (set-gl-state-screen-shader! state shader) + (set-gl-state-render-pass-draw-framebuffer! state draw-framebuffer) + (set-gl-state-render-pass-resolve-framebuffer! state resolve-framebuffer))) (define (gl-state-guard state obj) ((gl-state-guardian state) obj) @@ -1831,10 +1821,12 @@ void main (void) { ((gl-state-swap state))) (define (gl-state-begin-frame state) + (pk 'begin-frame (gl-get-error)) (set-gl-state-draw-framebuffer! state null-gl-framebuffer) (set-gl-state-read-framebuffer! state null-gl-framebuffer)) (define (gl-state-end-frame state view) + (pk 'end-frame (gl-get-error)) (swap-gl-state state view) (gl-state-gc state)) @@ -1850,55 +1842,103 @@ void main (void) { offset->pointer)) (define (gl-begin-render-pass state cmd) + (pk 'begin-render-pass (gl-get-error)) (match cmd (($ pass colors depth+stencil) - (let ((fbo (gl-state-framebuffer-build state pass colors depth+stencil))) + (let ((fbo (gl-state-render-pass-draw-framebuffer state))) (set-gl-state-draw-framebuffer! state fbo) ;; Disable scissor test so gl-clear will clear the entire ;; framebuffer. (set-gl-state-scissor-test! state #f) - ;; Clear all attachments that have a load op of 'clear'. + (pk 'begin-render-pass-1 (gl-get-error)) + ;; Setup color attachments. (let loop ((i 0)) (when (< i (vector-length colors)) (match (vector-ref colors i) - (#(#f _ _) #f) - (#(view resolve-target ($ clear-color 'clear)) - (set-gl-state-color-mask! state %default-color-mask) - (set-gl-state-clear-color! state clear-color) - ;; FIXME: Need to use glDrawBuffers for multiple color attachments. - (gl-draw-buffer (+ (version-3-0 color-attachment0) i)) - (gl-clear (clear-buffer-mask color-buffer)) - (loop (1+ i))) - (_ (loop (1+ i)))))) + (#(#f _ _) + (gl-framebuffer-texture-2d (version-3-0 framebuffer) + (+ (version-3-0 color-attachment0) i) + (texture-target texture-2d) + 0 0) + (pk 'begin-render-pass-3 (gl-get-error))) + (#((and ($ id target) view) resolve-target op) + (gl-framebuffer-texture-2d (version-3-0 framebuffer) + (+ (version-3-0 color-attachment0) i) + target id 0) + (pk 'framebuffer-status id target + (gl-check-framebuffer-status (version-3-0 framebuffer))) + (pk 'begin-render-pass-2 (gl-get-error)) + (match op + (($ clear-color 'clear) + (set-gl-state-color-mask! state %default-color-mask) + (set-gl-state-clear-color! state clear-color) + (gl-draw-buffer (+ (version-3-0 color-attachment0) i)) + (pk 'begin-render-pass-6 (gl-get-error)) + (gl-clear (clear-buffer-mask color-buffer)) + (pk 'begin-render-pass-7 (gl-get-error))) + (_ (values))) + (pk 'begin-render-pass-8 (gl-get-error)))) + (loop (1+ i)))) + (pk 'begin-render-pass-9 (gl-get-error)) + ;; Setup depth+stencil attachment. (match depth+stencil - (#(#f _ _) #f) - (#(view depth-op stencil-op) + (#(#f _ _) + (gl-framebuffer-texture-2d (version-3-0 framebuffer) + (arb-framebuffer-object depth-stencil-attachment) + (texture-target texture-2d) 0 0)) + (#(($ id target) depth-op stencil-op) + (gl-framebuffer-texture-2d (version-3-0 framebuffer) + (arb-framebuffer-object depth-stencil-attachment) + target id 0) (match depth-op (($ clear-value 'clear) (set-gl-state-depth-write! state #t) (set-gl-state-clear-depth! state clear-value) (gl-clear (clear-buffer-mask depth-buffer))) - (_ #t)) + (_ (values))) (match stencil-op (($ clear-value 'clear) (set-gl-state-stencil-write-mask! state #xff) (set-gl-state-clear-stencil! state clear-value) (gl-clear (clear-buffer-mask stencil-buffer))) - (_ #t)))))))) + (_ (values))))))))) -(define (gl-end-render-pass state) - ;;(set-gl-state-render-pass! state #f) - #t) +(define (gl-end-render-pass state cmd) + (match cmd + (($ resolve-targets) + (let ((read-fbo (gl-state-render-pass-draw-framebuffer state)) + (write-fbo (gl-state-render-pass-resolve-framebuffer state))) + (pk 'error-0 (gl-get-error)) + (set-gl-state-read-framebuffer! state read-fbo) + (set-gl-state-draw-framebuffer! state write-fbo) + (set-gl-state-scissor-test! state #f) + ;; Resolve color attachments with resolve targets. + (let loop ((i 0)) + (when (< i (vector-length resolve-targets)) + (match (vector-ref resolve-targets i) + (($ id target ($ _ _ width height)) + (gl-framebuffer-texture-2d (version-3-0 framebuffer) + (+ (version-3-0 color-attachment0) i) + target id 0) + (gl-draw-buffer (+ (version-3-0 color-attachment0) i)) + ;; TODO: Render a quad when framebuffer blit is unsupported. + (gl-blit-framebuffer 0 0 width height 0 0 width height + (clear-buffer-mask color-buffer) + (texture-mag-filter nearest)) + (pk 'blit-error (gl-get-error)) + (loop (1+ i))) + (#f (values))))))))) (define (gl-state-draw state cmd) + (pk 'draw-cmd (gl-get-error)) (match cmd (($ ($ shader begin-mode polygon-mode cull-face - front-face color-format blend-mode color-mask depth-test - stencil-test multisample vattrs binding-layout) + front-face color-format blend-mode color-mask depth-test + stencil-test multisample vattrs binding-layout) pass viewport scissor blend-constant stencil-reference start count instances index-buffer vertex-buffers bindings) - (set-gl-state-draw-framebuffer! state (gl-state-framebuffer-ref state pass)) + (set-gl-state-draw-framebuffer! state (gl-state-render-pass-draw-framebuffer state)) (set-gl-state-viewport! state viewport) (match scissor (#f (set-gl-state-scissor-test! state #f)) @@ -1933,7 +1973,7 @@ void main (void) { (match stencil-test (#f (set-gl-state-stencil-test! state #f)) (($ read-mask write-mask func-front func-back - op-front op-back) + op-front op-back) (set-gl-state-stencil-test! state #t) (set-gl-state-stencil-write-mask! state write-mask) (set-gl-state-stencil-op-front! state op-front) @@ -1942,7 +1982,11 @@ void main (void) { read-mask) (set-gl-state-stencil-func-back! state func-back stencil-reference read-mask))) - ;; TODO: Setup multisample state. + (match multisample + (#f (set-gl-state-multisample! state #f)) + (($ count mask alpha-to-coverage?) + ;; TODO: Set sample mask (when supported) + (set-gl-state-multisample! state #t))) ;; Setup vertex attributes. (do ((i 0 (+ i 1))) ((= i (vector-length vattrs))) @@ -1952,7 +1996,7 @@ void main (void) { ((= j (vector-length attrs))) (match (vector-ref attrs j) (($ index size type normalized? stride - pointer divisor) + pointer divisor) (gl-enable-vertex-attrib-array index) (gl-vertex-attrib-pointer index size type normalized? stride pointer) (when divisor @@ -2021,7 +2065,7 @@ void main (void) { ((begin-render-pass-command? cmd) (gl-begin-render-pass state cmd)) ((end-render-pass-command? cmd) - (gl-end-render-pass state)))) + (gl-end-render-pass state cmd)))) ;;; @@ -2039,6 +2083,8 @@ void main (void) { (extensions (let ((table (make-hash-table))) (for-each (lambda (name) + (display name) + (newline) (hash-set! table name #t)) (string-split (gl-get-string (string-name extensions)) #\space)) @@ -2093,6 +2139,7 @@ void main (void) { (hash-ref extensions "GL_ARB_texture_view") (hash-ref extensions "GL_ARB_sampler_objects") (hash-ref extensions "GL_ARB_uniform_buffer_object") + (hash-ref extensions "GL_EXT_framebuffer_blit") #f ; blending #f ; face culling #f ; depth test @@ -2136,8 +2183,8 @@ void main (void) { null-gl-shader null-gl-framebuffer null-gl-framebuffer - 'default ; mode - (make-weak-key-hash-table)))) + ;; mode + 'default))) (gl-state-init! gl-state) ;; Enable seamless cubemaps. There's never a need to disable it ;; so we don't need to track it in the GL state object. It only diff --git a/examples/path.scm b/examples/path.scm index 8f155e1..e22c6f3 100644 --- a/examples/path.scm +++ b/examples/path.scm @@ -60,7 +60,9 @@ (set-canvas-painter! canvas (make-example-painter s))))))) (define (draw alpha) + (pk 'draw-canvas) (draw-canvas canvas) + (pk 'draw-text) (draw-text stats-text stats-text-pos) (let ((current-time (elapsed-time))) (set! avg-frame-time -- cgit v1.2.3