luv

Workshop wiki

application-capture-tests.lisp

hal/application-capture-tests.lisp

system luv/test · 51 definitions · on GitHub

in-package#:luv.tests

A backend-free executable capture transaction. The probe keeps the GPU protocol real (descriptors, command encoding, submission, readback, and destruction) while replacing native resources with small Lisp objects.

defclasscapture-probe-resource
destroyed-p:initformnil:accessorcapture-probe-destroyed-p
defclasscapture-probe-texture
pixels:initarg:pixels:accessorcapture-probe-texture-pixels
defclasscapture-probe-buffer
data:initarg:data:accessorcapture-probe-buffer-data
defclasscapture-probe-encoder
device:initarg:device:readercapture-probe-encoder-device
commands:initformnil:accessorcapture-probe-encoder-commands
defclasscapture-probe-command-buffer
commands:initarg:commands:readercapture-probe-command-buffer-commands
defclasscapture-probe-device
queue:initform
make-instance'capture-probe-queue
:readercapture-probe-device-queue
resources:initformnil:accessorcapture-probe-device-resources
defmethodluv:device-queue
capture-probe-device-queuedevice
defmethodluv:create
descriptorluv::texture-descriptor
destructuring-bind
luv::texture-descriptor-sizedescriptor
declare
ignoredepth
let
texture
make-instance'capture-probe-texture:label
luv::gpu-descriptor-labeldescriptor
:size
luv::texture-descriptor-sizedescriptor
:usage
luv::texture-descriptor-usagedescriptor
:dimensions
luv::texture-descriptor-dimensionsdescriptor
:format
luv::texture-descriptor-formatdescriptor
:pixels
make-array:element-type'
unsigned-byte8
:initial-element0
pushtexture
capture-probe-device-resourcesdevice
texture
defmethodluv:create
descriptorluv::buffer-descriptor
let
buffer
make-instance'capture-probe-buffer:label
luv::gpu-descriptor-labeldescriptor
:size
luv::buffer-descriptor-sizedescriptor
:usage
luv::buffer-descriptor-usagedescriptor
:data
make-array
luv::buffer-descriptor-sizedescriptor
:element-type'
unsigned-byte8
:initial-element0
pushbuffer
capture-probe-device-resourcesdevice
buffer
defmethodluv:create
descriptorluv::command-encoder-descriptor
let
encoder
make-instance'capture-probe-encoder:label
luv::gpu-descriptor-labeldescriptor
:devicedevice
pushencoder
capture-probe-device-resourcesdevice
encoder
defmethodluv:encode
pushcommand
capture-probe-encoder-commandsencoder
command
defmethodluv:finish
let
commands
make-instance'capture-probe-command-buffer:commands
nreverse
capture-probe-encoder-commandsencoder
pushcommands
capture-probe-device-resources
capture-probe-encoder-deviceencoder
commands
defmethodluv:submit
declare
ignorequeue
dolist
command
capture-probe-command-buffer-commandscommands
when
typepcommand'luv::gpu-copy-texture-to-buffer-command
replace
capture-probe-buffer-data
luv::gpu-copy-texture-to-buffer-command-destinationcommand
capture-probe-texture-pixels
luv::gpu-copy-texture-to-buffer-command-sourcecommand
commands
defmethodluv:read-buffer
&keyoffsetsize
let*
offset
oroffset0
size
orsize
-
length
capture-probe-buffer-databuffer
offset
subseq
capture-probe-buffer-databuffer
offset
+offsetsize
defmethodluv:destroy
let
when
error"Injected capture probe ~A destruction failure."kind
setf
capture-probe-destroyed-presource
t
values
defclasscapture-probe-context
device:initarg:device:readercapture-probe-context-device
extent:initarg:extent:accessorcapture-probe-context-extent
format:initarg:format:accessorcapture-probe-context-format
defmethodluv:context-device
capture-probe-context-devicecontext
defmethodluv:canvas-extent
capture-probe-context-extentcontext
defmethodluv:canvas-format
capture-probe-context-formatcontext
defclasscapture-probe-canvas
context:initarg:context:readercapture-probe-canvas-context
state:initarg:state:initform:open:accessorcapture-probe-canvas-state
native-thread:initarg:native-thread:initformnil:readercapture-probe-canvas-native-thread
defmethodluv:canvas-context
capture-probe-canvas-contextcanvas
defmethodluv:canvas-state
capture-probe-canvas-statecanvas
defmethodluv:canvas-thread-p
eqsb-thread:*current-thread*
capture-probe-canvas-native-threadcanvas
defclasscapture-probe-application
canvas:initarg:canvas:readercapture-probe-application-canvas
events:initformnil:accessorcapture-probe-application-events
fail-encode-p:initarg:fail-encode-p:initformnil:readercapture-probe-fail-encode-p
fail-cleanup-p:initarg:fail-cleanup-p:initformnil:readercapture-probe-fail-cleanup-p
cleanup-saw-live-target-p:initformnil:accessorcapture-probe-cleanup-saw-live-target-p
defclassblocking-capture-probe-application
prepare-entered:initform
sb-thread:make-semaphore:name"capture prepare entered"
:readerblocking-capture-prepare-entered
prepare-release:initform
sb-thread:make-semaphore:name"capture prepare release"
:readerblocking-capture-prepare-release
defunnote-capture-probe-event
applicationevent
setf
capture-probe-application-eventsapplication
append
capture-probe-application-eventsapplication
listevent
defmethodluv:capture-canvas
capture-probe-application-canvasapplication
defmethodluv:prepare-capture
note-capture-probe-eventapplication:prepare
setf
luv:capture-client-statecapture
:prepared
defmethodluv:prepare-capture:after
declare
ignorecapture
sb-thread:signal-semaphore
blocking-capture-prepare-enteredapplication
unless
sb-thread:wait-on-semaphore
blocking-capture-prepare-releaseapplication
:timeout1.0
error"Blocking capture preparation timed out."
defmethodluv:advance-capture-frame
declare
ignorecapture
note-capture-probe-eventapplication
list:advanceframe-index
defmethodluv:encode-capture-frame
encodertargetextent
declare
ignoreencoderextent
let
frame
luv:capture-frame-indexcapture
note-capture-probe-eventapplication
list:encodeframe
when
capture-probe-fail-encode-papplication
error"Deliberate capture probe encoding failure."
let
value
+
luv:capture-optioncapture:pixel-value20
frame
pixels
capture-probe-texture-pixelstarget
loopforoffsetbelow
lengthpixels
by4do
setf
arefpixelsoffset
value
arefpixels
+offset1
value
arefpixels
+offset2
value
arefpixels
+offset3
255
luv:capture-optioncapture:metadata
defmethodluv:cleanup-capture
let
target
luv:capture-targetcapture
setf
capture-probe-cleanup-saw-live-target-papplication
andtarget
not
capture-probe-destroyed-ptarget
note-capture-probe-eventapplication:cleanup
when
capture-probe-fail-cleanup-papplication
error"Injected capture probe application cleanup failure."
defunmake-capture-probe-application
&keyfail-encode-pfail-cleanup-pnative-thread
let*
device
make-instance'capture-probe-device
context
make-instance'capture-probe-context:devicedevice:extent'
21
:format:rgba8-unorm
canvas
make-instance'capture-probe-canvas:contextcontext:native-threadnative-thread
values
make-instance'capture-probe-application:canvascanvas:fail-encode-pfail-encode-p:fail-cleanup-pfail-cleanup-p
devicecontext
defunmake-blocking-capture-probe-application
&keynative-thread
multiple-value-bind
applicationdevicecontext
make-capture-probe-application:native-threadnative-thread
values
make-instance'blocking-capture-probe-application:canvas
capture-probe-application-canvasapplication
devicecontext
deftestapplication-capture-shutdown-closes-admission-terminally
multiple-value-bind
applicationdevice
let*
requested
make-instance'luv:application-capture:applicationapplication:kind:screenshot:label"late screenshot"
published-pnil
conditionnil
handler-case
luv::call-with-capture-target
lambda
capture
declare
ignorecapture
:wrong
requested
luv:application-capture-shutting-down
failure
setfconditionfailure
okcondition
ok
eqapplication
luv:application-capture-shutting-down-applicationcondition
ok
eqrequested
luv:application-capture-shutting-down-requested-capturecondition
ok
not
luv:call-if-application-captures-openapplication
lambda
setfpublished-pt
ok
notpublished-p
ok
null
capture-probe-application-eventsapplication
ok
null
capture-probe-device-resourcesdevice
deftestcapture-shutdown-waits-off-canvas-and-rejects-late-captures
multiple-value-bind
applicationdevice
let*
active
make-instance'luv:application-capture:applicationapplication:kind:film:label"draining film"
late
make-instance'luv:application-capture:applicationapplication:kind:screenshot:label"late screenshot"
active-conditionnil
drain-conditionnil
drained
sb-thread:make-semaphore:name"capture shutdown drained"
active-thread
sb-thread:make-thread
lambda
handler-case
luv::call-with-capture-target
lambda
capture
declare
ignorecapture
:finished
active
error
condition
setfactive-conditioncondition
:name"capture active during shutdown test"
ok
sb-thread:wait-on-semaphore
blocking-capture-prepare-enteredapplication
:timeout1.0
ok
signals
luv::call-with-capture-target
lambda
capture
declare
ignorecapture
:wrong
late
'luv:application-capture-shutting-down
let
drainer
sb-thread:make-thread
lambda
handler-case
error
condition
setfdrain-conditioncondition
sb-thread:signal-semaphoredrained
:name"application capture shutdown test"

The stop owner has closed admission but cannot pass the active capture until its preparation and cleanup have both left.

ok
not
sb-thread:wait-on-semaphoredrained:timeout0.05
sb-thread:signal-semaphore
blocking-capture-prepare-releaseapplication
sb-thread:join-threadactive-thread
ok
sb-thread:wait-on-semaphoredrained:timeout1.0
sb-thread:join-threaddrainer
ok
nullactive-condition
ok
nulldrain-condition
ok
equal'
:prepare:cleanup
capture-probe-application-eventsapplication
ok
every#'capture-probe-destroyed-p
capture-probe-device-resourcesdevice
deftestcanvas-thread-cannot-wait-for-an-active-capture
multiple-value-bind
applicationdevice
make-blocking-capture-probe-application:native-threadsb-thread:*current-thread*
declare
ignoredevice
let*
active
make-instance'luv:application-capture:applicationapplication:kind:film:label"canvas-blocking film"
active-conditionnil
thread
sb-thread:make-thread
lambda
handler-case
luv::call-with-capture-target
lambda
capture
declare
ignorecapture
:finished
active
error
condition
setfactive-conditioncondition
:name"canvas-blocking capture test"
ok
sb-thread:wait-on-semaphore
blocking-capture-prepare-enteredapplication
:timeout1.0
let
okcondition
ok
eqapplication
luv:application-capture-shutdown-blocking-applicationcondition
ok
eqactive
luv:application-capture-shutdown-blocking-active-capturecondition
sb-thread:signal-semaphore
blocking-capture-prepare-releaseapplication
sb-thread:join-threadthread
ok
nullactive-condition

Once the owner has left, quiescence is immediate even on this thread.

ok
null
multiple-value-list
deftestoverlapping-application-captures-fail-before-preparation
multiple-value-bind
applicationdevice
let*
active
make-instance'luv:application-capture:applicationapplication:kind:film:label"active film"
requested
make-instance'luv:application-capture:applicationapplication:kind:screenshot:label"overlapping screenshot"
active-resultnil
active-conditionnil
thread
sb-thread:make-thread
lambda
handler-case
setfactive-result
luv::call-with-capture-target
lambda
capture
declare
ignorecapture
:finished
active
error
condition
setfactive-conditioncondition
:name"active application capture test"
ok
sb-thread:wait-on-semaphore
blocking-capture-prepare-enteredapplication
:timeout1.0
let
condition
handler-case
progn
luv::call-with-capture-target
lambda
capture
declare
ignorecapture
:overlapped
requested
nil
okcondition
ok
eqapplication
luv:application-capture-busy-applicationcondition
ok
eqactive
luv:application-capture-busy-active-capturecondition
ok
eqrequested
luv:application-capture-busy-requested-capturecondition

The rejected capture performed no preparation and allocated no GPU resource. Let the exact active owner finish and release its claim.

ok
equal'
:prepare
capture-probe-application-eventsapplication
ok
null
capture-probe-device-resourcesdevice
sb-thread:signal-semaphore
blocking-capture-prepare-releaseapplication
sb-thread:join-threadthread
ok
nullactive-condition
ok
eq:finishedactive-result
ok
equal'
:prepare:cleanup
capture-probe-application-eventsapplication
ok
every#'capture-probe-destroyed-p
capture-probe-device-resourcesdevice
deftestfailed-capture-body-does-not-strand-the-application-reservation
multiple-value-bind
applicationdevice
let
first
make-instance'luv:application-capture:applicationapplication:kind:screenshot
second
make-instance'luv:application-capture:applicationapplication:kind:screenshot
ok
signals
luv::call-with-capture-target
lambda
capture
declare
ignorecapture
error"Injected reserved capture body failure."
first
'error
ok
eq:recovered
luv::call-with-capture-target
lambda
capture
declare
ignorecapture
:recovered
second
ok
equal'
:prepare:cleanup:prepare:cleanup
capture-probe-application-eventsapplication
ok
every#'capture-probe-destroyed-p
capture-probe-device-resourcesdevice
deftestapplication-screenshot-is-one-owned-offscreen-transaction
multiple-value-bind
applicationdevice
let*
directory
uiop:ensure-directory-pathname
merge-pathnames
formatnil"luv-application-capture-test-~36R/"
randommost-positive-fixnum
uiop:temporary-directory
pathname
merge-pathnames"frame.png"directory
unwind-protect
multiple-value-bind
writtenpixelswidthheightformatmetadata
luv:capture-application-screenshotapplicationpathname:options'
:pixel-value37:metadata:frame-metadata
:label"capture probe screenshot"
ok
equalpathnamewritten
ok
probe-filepathname
ok
eq:rgba8-unormformat
ok
eq:frame-metadatametadata
ok
equalp
373737255373737255
pixels
ok
equal'
:prepare
:encode0
:cleanup
capture-probe-application-eventsapplication
ok
capture-probe-cleanup-saw-live-target-papplication
ok
every#'capture-probe-destroyed-p
capture-probe-device-resourcesdevice
uiop:delete-directory-treedirectory:validatet:if-does-not-exist:ignore
deftestfailed-frame-encoding-still-cleans-up-application-and-gpu-resources
multiple-value-bind
applicationdevice
let*
capture
make-instance'luv:application-capture:applicationapplication:kind:screenshot
condition
handler-case
error
error
error
okcondition
ok
search"Deliberate capture probe"
princ-to-stringcondition
ok
equal'
:prepare
:encode0
:cleanup
capture-probe-application-eventsapplication
ok
capture-probe-cleanup-saw-live-target-papplication
ok
every#'capture-probe-destroyed-p
capture-probe-device-resourcesdevice
deftestcapture-cleanup-failures-cannot-mask-the-frame-failure
multiple-value-bind
applicationdevice
make-capture-probe-application:fail-encode-pt:fail-cleanup-pt
declare
ignoredevice
let*
*capture-probe-destroy-failures*'
:encoder:readback:target
warningsnil
capture
make-instance'luv:application-capture:applicationapplication:kind:screenshot
condition
handler-bind
luv:release-warning
lambda
warning
setfwarnings
appendwarnings
listwarning
muffle-warningwarning
handler-case
error
error
error
okcondition
ok
search"Deliberate capture probe encoding failure"
princ-to-stringcondition
ok
equal'
:prepare
:encode0
:cleanup
capture-probe-application-eventsapplication
ok
equal'
:encoder:readback:target
*capture-probe-destroy-events*
ok
equal'
:capture-frame-encoder:capture-application-cleanup:capture-readback-buffer:capture-target
loopforwarninginwarningsappend
mapcar#'luv:release-failure-name
luv:release-warning-failureswarning
deftestfilm-frames-preserve-hook-order-and-use-absolute-deadlines
multiple-value-bind
applicationdevice
declare
ignoredevice
let*
capture
make-instance'luv:application-capture:applicationapplication:kind:film:options'
:pixel-value40
clock-values'
10.0d010.1d010.7d011.6d0
waitsnil
luv::call-with-capture-target
lambda
capture
luv::call-with-capture-film-frames
lambda
pixels
note-capture-probe-eventapplication
list:write
luv:capture-frame-indexcapture
arefpixels0
capture32:before-frame
lambda
note-capture-probe-eventapplication
list:beforeframe
:progress-function
lambda
framecount
note-capture-probe-eventapplication
list:progressframecount
:clock-function
lambda
popclock-values
:sleep-function
lambda
seconds
pushsecondswaits
capture
ok
equal'
:prepare
:before0
:advance0
:encode0
:write040
:progress03
:before1
:advance1
:encode1
:write141
:progress13
:before2
:advance2
:encode2
:write242
:progress23
:cleanup
capture-probe-application-eventsapplication
ok
=2
lengthwaits
ok
<
abs
-0.4d0
secondwaits
1.0d-9
ok
<
abs
-0.3d0
firstwaits
1.0d-9
deftestshutdown-cooperatively-shortens-an-active-film
multiple-value-bind
applicationdevice
declare
ignoredevice
let
capture
make-instance'luv:application-capture:applicationapplication:kind:film
clock-values'
10.0d010.1d0
waitsnil
luv::call-with-capture-target
lambda
capture
luv::call-with-capture-film-frames
lambda
pixels
declare
ignorepixels
note-capture-probe-eventapplication:write
capture202:clock-function
lambda
popclock-values
:sleep-function
lambda
seconds
pushsecondswaits
capture
ok
equal'
:prepare
:advance0
:encode0
:write:cleanup
capture-probe-application-eventsapplication
ok
nullwaits
ok
nullclock-values
deftestcapture-rejects-an-extent-change-before-encoding
multiple-value-bind
applicationdevicecontext
let
capture
make-instance'luv:application-capture:applicationapplication:kind:screenshot
ok
signals
luv::call-with-capture-target
lambda
capture
setf
capture-probe-context-extentcontext
'
31
capture
'error
ok
equal'
:prepare:cleanup
capture-probe-application-eventsapplication
ok
capture-probe-cleanup-saw-live-target-papplication
ok
every#'capture-probe-destroyed-p
capture-probe-device-resourcesdevice
deftestcapture-rejects-a-format-change-before-encoding
multiple-value-bind
applicationdevicecontext
let
capture
make-instance'luv:application-capture:applicationapplication:kind:screenshot
ok
signals
luv::call-with-capture-target
lambda
capture
setf
capture-probe-context-formatcontext
:bgra8-unorm
capture
'error
ok
equal'
:prepare:cleanup
capture-probe-application-eventsapplication
ok
capture-probe-cleanup-saw-live-target-papplication
ok
every#'capture-probe-destroyed-p
capture-probe-device-resourcesdevice