# testDrawReadPixels.tcl
#
# Tcl3D demo testing the speed of the glDrawPixels and glReadPixels functions.
# The program generates a color gradient image of a specified size.
# If the image size is greater than 256x256, the color gradient is tiled.
# This image is then drawn into the framebuffer with glDrawPixels and read
# back with glReadPixels several times.
# The time needed for drawing and reading back is reported into a text widget
# and onto stdout (for batch processing).
# The format and type of the image data can be specified for testing the
# differences in speed.
# Currently the following formats and types are implemented:
# Formats: GL_RGB, GL_BGR, GL_RGBA, GL_BGRA.
# Types : GL_UNSIGNED_BYTE
#
# Author: Paul Obermeier
# Date: 2009-07-16
package require tcl3d
# Font to be used in the Tk listbox.
set gDemo(listFont) {-family {Courier} -size 10}
# Determine the directory of this script
set gDemo(scriptDir) [file dirname [info script]]
# The possible formats and types.
set g_formats(GL_RGB,enum) $::GL_RGB
set g_formats(GL_BGR,enum) $::GL_BGR
set g_formats(GL_RGBA,enum) $::GL_RGBA
set g_formats(GL_BGRA,enum) $::GL_BGRA
set g_formats(GL_RGB,numChans) 3
set g_formats(GL_BGR,numChans) 3
set g_formats(GL_RGBA,numChans) 4
set g_formats(GL_BGRA,numChans) 4
set g_types(GL_UNSIGNED_BYTE,enum) $::GL_UNSIGNED_BYTE
set g_types(GL_UNSIGNED_BYTE,numBytes) 1
foreach fmt [lsort [array names g_formats "*,enum"]] {
lappend gOpts(formatsList) [lindex [split $fmt ","] 0]
}
foreach type [lsort [array names g_types "*,enum"]] {
lappend gOpts(typesList) [lindex [split $type ","] 0]
}
# Default values for optional parameters.
set gOpts(curFormat) GL_RGB
set gOpts(curType) GL_UNSIGNED_BYTE
set gOpts(imgWidth) 256
set gOpts(imgHeight) 256
set gOpts(imgSize) [format "%dx%d" $gOpts(imgWidth) $gOpts(imgHeight)]
set gOpts(numCalls) 100
set gOpts(batch) false
set gDemo(winWidth) $gOpts(imgWidth)
set gDemo(winHeight) $gOpts(imgHeight)
set gDemo(lastFormat) $gOpts(curFormat)
# Show errors occuring in the Togl callbacks.
proc bgerror { msg } {
tk_messageBox -icon error -type ok -message "Error: $msg\n\n$::errorInfo"
exit
}
# Print info message into label widget at the bottom of the window.
proc PrintInfo { msg } {
if { [winfo exists .fr.info] } {
.fr.info configure -text $msg
}
}
# Print report message into text widget at the bottom of the window.
proc PrintReport { msg } {
global gDemo
if { [winfo exists $gDemo(out)] } {
$gDemo(out) insert end "$msg\n"
$gDemo(out) see end
}
puts $msg
}
# Save the image stored in tcl3dVector "vec" into file "fileName".
proc SaveImg { fileName vec w h numChans } {
set ph [image create photo -width $w -height $h]
tcl3dVectorToPhoto $vec $ph $w $h $numChans
set fmt [string range [file extension $fileName] 1 end]
$ph write $fileName -format $fmt
image delete $ph
}
# Create an image of size (w x h) with numChans channels.
proc MakeImg { w h numChans } {
global gOpts gDemo
if { $numChans == 3 } {
set template [binary format ccc 1 0 0]
for { set j 1 } { $j < $w } { incr j } {
append template [binary format ccc $j 0 0]
}
} elseif { $numChans == 4 } {
set template [binary format cccc 1 0 0 0]
for { set j 1 } { $j < $w } { incr j } {
append template [binary format cccc $j 0 0 0]
}
} else {
error "Cannot make an image with $numChans channels"
}
set row $template
for { set i 0 } { $i < $gOpts(imgHeight) } { incr i } {
append img $row
set row [string map [list [binary format c 0] [binary format c $i]] \
$template]
}
set gDemo(imgVec) [tcl3dVectorFromByteArray GLubyte $img]
}
proc NewSquareImage {} {
global gOpts
scan $gOpts(imgSize) "%dx%d" gOpts(imgWidth) gOpts(imgHeight)
if { $gOpts(imgWidth) < 1 } {
set gOpts(imgWidth) 1
}
if { $gOpts(imgHeight) < 1 } {
set gOpts(imgHeight) 1
}
set gOpts(imgSize) [format "%dx%d" $gOpts(imgWidth) $gOpts(imgHeight)]
NewImage
.fr.toglwin configure -width $gOpts(imgWidth) -height $gOpts(imgHeight)
}
proc NewImage {} {
global gOpts g_formats g_types
Cleanup true
set curFmt $gOpts(curFormat)
MakeImg $gOpts(imgWidth) $gOpts(imgHeight) $g_formats($curFmt,numChans)
}
proc ReadPixels { vec w h } {
global gOpts g_formats g_types
set fmt $g_formats($gOpts(curFormat),enum)
set type $g_types($gOpts(curType),enum)
glReadPixels 0 0 $w $h $fmt $type $vec
}
proc DrawPixels { vec w h } {
global gOpts g_formats g_types
set fmt $g_formats($gOpts(curFormat),enum)
set type $g_types($gOpts(curType),enum)
glDrawPixels $w $h $fmt $type $vec
}
proc TimedDrawReadPixels {} {
global gOpts gDemo g_formats
set w $gOpts(imgWidth)
set h $gOpts(imgHeight)
set numChans $g_formats($gOpts(curFormat),numChans)
set imgVec [tcl3dVector GLubyte [expr $w * $h * $numChans]]
glPixelStorei GL_PACK_ALIGNMENT 1
NewImage
set measure [time {DrawPixels $gDemo(imgVec) $w $h} $gOpts(numCalls)]
scan $measure "%f" msDraw
set measure [time {ReadPixels $imgVec $w $h} $gOpts(numCalls)]
scan $measure "%f" msRead
set totDraw [format "%.4f" [expr $msDraw * $gOpts(numCalls) / 1000000.0]]
set imgDraw [format "%.4f" [expr $msDraw / 1000.0]]
set pixDraw [format "%.4f" [expr $msDraw / $w / $h]]
set totRead [format "%.4f" [expr $msRead * $gOpts(numCalls) / 1000000.0]]
set imgRead [format "%.4f" [expr $msRead / 1000.0]]
set pixRead [format "%.4f" [expr $msRead / $w / $h]]
PrintReport "Draw/Read of $gOpts(numCalls) images: $totDraw $totRead secs"
PrintReport "Draw/Read of 1 image: $imgDraw $imgRead msecs ([expr $w*$h] pixels)"
PrintReport "Draw/Read of 1 pixel: $pixDraw $pixRead msecs"
# Write out the last read image.
set fileName [format "%s-%dx%d.png" $gOpts(curFormat) $w $h]
set filePath [file join $gDemo(scriptDir) $fileName]
# Create a name on the file system, if running from within a Starpack.
set imgName [tcl3dGenExtName $filePath]
PrintReport "Saving image to [file tail $imgName]"
SaveImg $imgName $imgVec $w $h $numChans
$imgVec delete
}
proc CreateCallback { toglwin } {
glClearColor 0.0 0.0 0.0 0.0
glShadeModel GL_FLAT
glEnable GL_DEPTH_TEST
}
proc ReshapeCallback { toglwin { w -1 } { h -1 } } {
global gOpts gDemo
set w [$toglwin width]
set h [$toglwin height]
glViewport 0 0 $w $h
glMatrixMode GL_PROJECTION
glLoadIdentity
glOrtho 0 $gOpts(imgWidth) 0 $gOpts(imgHeight) -1.0 1.0
glMatrixMode GL_MODELVIEW
set gDemo(winWidth) $w
set gDemo(winHeight) $h
}
proc DisplayCallback { toglwin } {
global gOpts gDemo
glClear [expr $::GL_COLOR_BUFFER_BIT | $::GL_DEPTH_BUFFER_BIT]
# Viewport command is not really needed, but has been inserted for
# Mac OSX. Presentation framework (Tk) does not send a reshape event,
# when switching from one demo to another.
glViewport 0 0 [$toglwin width] [$toglwin height]
glRasterPos2i 0 0
if { $gOpts(curFormat) ne $gDemo(lastFormat) } {
set gDemo(lastFormat) $gOpts(curFormat)
NewImage
}
DrawPixels $gDemo(imgVec) $gOpts(imgWidth) $gOpts(imgHeight)
glFlush
$toglwin swapbuffers
}
proc ExecTest {} {
TimedDrawReadPixels
.fr.toglwin postredisplay
}
proc Cleanup { { imgOnly false } } {
global gDemo
if { [info exists gDemo(imgVec)] } {
$gDemo(imgVec) delete
}
if { ! $imgOnly } {
foreach var [info globals g_*] {
uplevel #0 unset $var
}
uplevel #0 unset gDemo
uplevel #0 unset gOpts
}
}
proc ExitProg {} {
exit
}
# Create the widgets and bindings.
proc CreateWindow {} {
global gDemo gOpts
frame .fr
pack .fr -expand 1 -fill both
# Create the OpenGL widget.
togl .fr.toglwin -width $gDemo(winWidth) -height $gDemo(winHeight) \
-double true -depth true -alpha true \
-createcommand CreateCallback \
-reshapecommand ReshapeCallback \
-displaycommand DisplayCallback
frame .fr.frBtns
frame .fr.frReport
label .fr.info
grid .fr.toglwin -row 0 -column 0 -sticky news
grid .fr.frBtns -row 1 -column 0 -sticky news
grid .fr.frReport -row 2 -column 0 -sticky news
grid .fr.info -row 3 -column 0 -sticky news
grid rowconfigure .fr 0 -weight 1
grid columnconfigure .fr 0 -weight 1
wm title . "Tcl3D demo: Speed test of glDrawPixels and glReadPixels"
labelframe .fr.frBtns.frSett -text "Format and type"
pack .fr.frBtns.frSett -side left -padx 2
set gOpts(formatsMenu) [eval {tk_optionMenu .fr.frBtns.frSett.fm \
gOpts(curFormat)} $gOpts(formatsList)]
set gOpts(typesMenu) [eval {tk_optionMenu .fr.frBtns.frSett.tm \
gOpts(curType)} $gOpts(typesList)]
eval pack [winfo children .fr.frBtns.frSett] -side left \
-anchor w -expand 1 -fill x
labelframe .fr.frBtns.frSize -text "Image size"
pack .fr.frBtns.frSize -side left -padx 2
entry .fr.frBtns.frSize.size -textvariable gOpts(imgSize) -width 8
bind .fr.frBtns.frSize.size <Key-Return> "NewSquareImage"
tcl3dToolhelpAddBinding .fr.frBtns.frSize.size \
"Press Enter to generate a new image. Resize the window to fit the image."
eval pack [winfo children .fr.frBtns.frSize] -side left \
-anchor w -expand 1 -fill x
labelframe .fr.frBtns.frMisc -text "Num calls"
pack .fr.frBtns.frMisc -side left -padx 2
entry .fr.frBtns.frMisc.numCalls -textvariable gOpts(numCalls) -width 4
bind .fr.frBtns.frMisc.numCalls <Key-Return> "ExecTest"
tcl3dToolhelpAddBinding .fr.frBtns.frMisc.numCalls \
"Number of glDrawPixels and glReadPixels calls executed in test."
eval pack [winfo children .fr.frBtns.frMisc] -side left \
-anchor w -expand 1 -fill x
labelframe .fr.frBtns.frCmds -text "Test"
pack .fr.frBtns.frCmds -side left -padx 2
button .fr.frBtns.frCmds.exe -text "Run" -command "ExecTest"
eval pack [winfo children .fr.frBtns.frCmds] -side left \
-anchor w -expand 1 -fill x -padx 1
set gDemo(out) [tcl3dCreateScrolledText .fr.frReport "" \
-height 5 -width 60 -borderwidth 1 -font $gDemo(listFont)]
wm protocol . WM_DELETE_WINDOW "ExitProg"
bind . <Key-Escape> "ExitProg"
}
set i 0
while { $i < $argc } {
set curArg [lindex $argv $i]
if { $curArg eq "-help" || $curArg eq "--help" } {
puts "Usage: $argv0 \[Options\]"
puts "Options:"
puts " -size w h: Specify image width and height"
puts " -num n : Specify number of draw and read calls"
puts " -batch : Execute test and quit"
puts " -format : Specify image format (GL_RGB, GL_BGR, ...)"
puts " -type : Specify image type (GL_UNSIGNED_BYTE)"
ExitProg
} elseif { $curArg eq "-size" } {
incr i
set gOpts(imgWidth) [lindex $argv $i]
incr i
set gOpts(imgHeight) [lindex $argv $i]
set gOpts(imgSize) [format "%dx%d" $gOpts(imgWidth) $gOpts(imgHeight)]
set gDemo(winWidth) $gOpts(imgWidth)
set gDemo(winHeight) $gOpts(imgHeight)
} elseif { $curArg eq "-num" } {
incr i
set gOpts(numCalls) [lindex $argv $i]
} elseif { $curArg eq "-format" } {
incr i
set gOpts(curFormat) [lindex $argv $i]
if { [lsearch $gOpts(formatsList) $gOpts(curFormat)] < 0 } {
puts "Unknown format $gOpts(curFormat)"
puts "Formats available: $gOpts(formatsList)"
ExitProg
}
} elseif { $curArg eq "-type" } {
incr i
set gOpts(curType) [lindex $argv $i]
if { [lsearch $gOpts(typesList) $gOpts(curType)] < 0 } {
puts "Unknown type $gOpts(curType)"
puts "Types available: $gOpts(typesList)"
ExitProg
}
} elseif { $curArg eq "-batch" } {
set gOpts(batch) true
} else {
puts "Ignoring unknown option $curArg"
}
incr i
}
CreateWindow
NewImage
PrintInfo [tcl3dOglGetInfoString]
if { $gOpts(batch) } {
update
TimedDrawReadPixels
ExitProg
}
|