CMSC23740 Common Code Library
Support code for CS23740 programming projects
Loading...
Searching...
No Matches
window.hpp
Go to the documentation of this file.
1
8/*
9 * COPYRIGHT (c) 2024 John Reppy (https://cs.uchicago.edu/~jhr)
10 * All rights reserved.
11 */
12
13#ifndef _CS237_WINDOW_HPP_
14#define _CS237_WINDOW_HPP_
15
16#ifndef _CS237_HPP_
17#error "cs237/window.hpp should not be included directly"
18#endif
19
20#include <optional>
21
22namespace cs237 {
23
24#ifdef CS237_MAX_FRAMES_IN_FLIGHT
25# define MAX_FRAMES CS237_MAX_FRAMES_IN_FLIGHT
26#else
27# define MAX_FRAMES 2
28#endif
29
33constexpr int kMaxFrames = MAX_FRAMES;
34
36//
38 int wid;
39 int ht;
40 std::string title;
41 bool resizable;
42 bool depth;
43 bool stencil;
44
52 CreateWindowInfo (int w, int h, std::string const &t, bool r, bool d, bool s)
53 : wid(w), ht(h), title(t), resizable(r), depth(d), stencil(s)
54 { }
55
59 CreateWindowInfo (int w, int h)
60 : wid(w), ht(h), title(""), resizable(false), depth(false), stencil(false)
61 { }
62
64 bool needsDepthBuf () const { return this->depth || this->stencil; }
65};
66
68//
69class Window {
70public:
71
73 virtual ~Window ();
74
78 void initialize ();
79
81 Application *app () { return this->_app; }
82
84 vk::Device device () const { return this->_app->_device; }
85
87 vk::Queue graphicsQ () const { return this->_app->_queues.graphics; }
88
90 vk::Queue presentationQ () const { return this->_app->_queues.present; }
91
93 vk::Queue computeQ () const { return this->_app->_queues.compute; }
94
97 void refresh ()
98 {
99 if (this->_isVis) {
100 this->draw();
101 }
102 }
103
105 void hide ()
106 {
107 glfwHideWindow (this->_win);
108 this->_isVis = false;
109 }
110
112 void show ()
113 {
114 glfwShowWindow (this->_win);
115 this->_isVis = true;
116 }
117
120 virtual void draw () = 0;
121
129 virtual void reshape (int wid, int ht);
130
132 virtual void iconify (bool iconified);
133
136 {
137 return glfwWindowShouldClose (this->_win);
138 }
139
143 virtual void key (int key, int scancode, int action, int mods);
144 virtual void cursorPos (double xpos, double ypos);
145 virtual void cursorEnter (bool entered);
146 virtual void mouseButton (int button, int action, int mods);
147 virtual void scroll (double xoffset, double yoffset);
148 //}
149
152 void enableKeyEvent (bool enable);
153 void setCursorMode (int mode);
154 void enableCursorPosEvent (bool enable);
155 void enableCursorEnterEvent (bool enable);
156 void enableMouseButtonEvent (bool enable);
157 void enableScrollEvent (bool enable);
158 //}
159
160protected:
163 vk::SurfaceCapabilitiesKHR capabilities;
164 std::vector<vk::SurfaceFormatKHR> formats;
165 std::vector<vk::PresentModeKHR> presentModes;
166
168 vk::SurfaceFormatKHR chooseSurfaceFormat ();
171 vk::PresentModeKHR choosePresentMode ();
174 vk::Extent2D chooseExtent (GLFWwindow *win);
175 };
176
179 bool depth;
180 bool stencil;
181 vk::Format format;
182 vk::Image image;
183 vk::DeviceMemory imageMem;
184 vk::ImageView view;
185 };
186
188 struct SwapChain {
189 vk::Device device;
190 vk::SwapchainKHR chain;
191 vk::Format imageFormat;
192 vk::Extent2D extent;
194 // the following vectors hold the state for each of the buffers in the
195 // swap chain.
196 std::vector<vk::Image> images;
197 std::vector<vk::ImageView> views;
198 std::optional<DepthStencilBuffer> dsBuf;
199 std::vector<vk::Framebuffer> fBufs;
200
201 SwapChain (vk::Device dev)
202 : device(dev), dsBuf(std::nullopt)
203 { }
204
206 int size () const { return this->images.size(); }
207
210 void initFramebuffers (vk::RenderPass renderPass);
211
213 bool hasDepthBuffer () const
214 {
215 return this->dsBuf.has_value() && this->dsBuf->depth;
216 }
217
219 bool hasStencilBuffer () const
220 {
221 return this->dsBuf.has_value() && this->dsBuf->stencil;
222 }
223
226 std::optional<vk::ImageView> depthImageView ()
227 {
228 if (this->dsBuf.has_value()) {
229 return dsBuf->view;
230 } else {
231 // no depth buffer
232 return std::optional<vk::ImageView>();
233 }
234 }
235
237 void cleanup ();
238 };
239
246 struct FrameData {
248 vk::CommandBuffer cmdBuf;
250 vk::Semaphore imageAvail;
252 vk::Semaphore finished;
254 vk::Fence inFlight;
256 uint32_t index;
259
264 //
266
267 FrameData () = delete;
268 FrameData (FrameData &) = delete;
269 FrameData (FrameData const &) = delete;
270 FrameData (FrameData &&) = delete;
271
273 //
274 virtual ~FrameData ();
275
278 {
279 auto sts = this->win->device().waitForFences(this->inFlight, VK_TRUE, UINT64_MAX);
280 if (sts != vk::Result::eSuccess) {
281 ERROR("Synchronization error");
282 }
283 }
284
287 {
288 this->win->device().resetFences(this->inFlight);
289 }
290
293
296 vk::Result present ()
297 {
298 vk::PresentInfoKHR presentInfo(
299 this->finished,
300 this->win->_swap.chain,
301 this->index,
302 nullptr);
303
304 return this->win->presentationQ().presentKHR(presentInfo);
305 }
306
307 }; // struct FrameData
308
310 GLFWwindow *_win;
311 int _wid, _ht;
312 bool _isVis;
318 // Vulkan state for rendering
319 vk::SurfaceKHR _surf;
322 uint32_t _curFrameIdx;
324
329
332 virtual void _init ();
333
336
341 void _createSwapChain (bool depth, bool stencil);
342
347
353
355 FrameData *_currentFrame () { return this->_frames[this->_curFrameIdx]; }
356
359 {
360 if (this->_curFrameIdx == 0) {
361 return this->_frames[kMaxFrames - 1];
362 } else {
363 return this->_frames[this->_curFrameIdx - 1];
364 }
365 }
366
369 {
370 return this->_frames[(this->_curFrameIdx + 1) % kMaxFrames];
371 }
372
374 void _advanceFrame () { this->_curFrameIdx = (this->_curFrameIdx + 1) % kMaxFrames; }
375
380 vk::Result _acquireNextImage ();
381
387 std::vector<vk::AttachmentDescription> &descs,
388 std::vector<vk::AttachmentReference> &refs);
389
393 uint32_t _graphicsQIdx () const { return this->_app->_qIdxs.graphics; }
394
398 uint32_t _presentationQIdx () const { return this->_app->_qIdxs.present; }
399
403 uint32_t _computeQIdx () const { return this->_app->_qIdxs.compute; }
404
410 vk::Viewport _getViewport (bool oglView = false)
411 {
412 if (oglView) {
413 // to get the OpenGL-style viewport, we set the origin at Y = height
414 // and use a negative height
415 return vk::Viewport(
416 0.0f,
417 float(this->_swap.extent.width),
418 float(this->_swap.extent.width),
419 -float(this->_swap.extent.height),
420 0.0f, /* min depth */
421 1.0f);
422 } else {
423 return vk::Viewport(
424 0.0f, 0.0f,
425 float(this->_swap.extent.width),
426 float(this->_swap.extent.height),
427 0.0f, /* min depth */
428 1.0f); /* max depth */
429 }
430 }
431
434 vk::Rect2D _getScissorsRect ()
435 {
436 return vk::Rect2D(
437 {0, 0},
438 {this->_swap.extent.width, this->_swap.extent.height});
439 }
440
451 void _setViewportCmd (vk::CommandBuffer cmdBuf, bool oglView = false)
452 {
453 if (oglView) {
454 /* NOTE: we negate the height and set the Y origin to ht because Vulkan's
455 * viewport coordinates are from top-left down, instead of from
456 * bottom-left up. See
457 * https://www.saschawillems.de/blog/2019/03/29/flipping-the-vulkan-viewport
458 */
459 this->_setViewportCmd(cmdBuf,
460 0, this->_swap.extent.height,
461 this->_swap.extent.width, -(int32_t)this->_swap.extent.height);
462 } else {
463 this->_setViewportCmd(cmdBuf,
464 0, 0,
465 this->_swap.extent.width, this->_swap.extent.height);
466 }
467 }
468
479 void _setViewportCmd (vk::CommandBuffer cmdBuf,
480 int32_t x, int32_t y,
481 int32_t wid, int32_t ht);
482
487 vk::DeviceMemory _allocImageMemory (vk::Image img, vk::MemoryPropertyFlags props)
488 {
489 return this->_app->_allocImageMemory (img, props);
490 }
491
498 vk::ImageView _createImageView (
499 vk::Image img, vk::Format fmt, vk::ImageAspectFlags aspectFlags)
500 {
501 return this->_app->_createImageView (img, fmt, aspectFlags);
502 }
503
510 vk::Image img,
511 vk::Format fmt,
512 vk::ImageLayout oldLayout,
513 vk::ImageLayout newLayout)
514 {
515 this->_app->_transitionImageLayout(img, fmt, oldLayout, newLayout);
516 }
517
518public:
519
521 int width () const { return this->_swap.extent.width; }
522
524 int height () const { return this->_swap.extent.height; }
525
526};
527
528} // namespace cs237
529
530#endif // !_CS237_WINDOW_HPP_
the base class for applications
Definition application.hpp:25
vk::Device _device
the logical device that we are using to render
Definition application.hpp:443
Queues< uint32_t > _qIdxs
the queue family indices
Definition application.hpp:444
void _transitionImageLayout(vk::Image img, vk::Format fmt, vk::ImageLayout oldLayout, vk::ImageLayout newLayout)
A helper function for changing the layout of an image.
vk::ImageView _createImageView(vk::Image img, vk::Format fmt, vk::ImageAspectFlags aspectFlags)
A helper function for creating a Vulkan image view object for an image.
Queues< vk::Queue > _queues
the device queues that we are using
Definition application.hpp:445
vk::DeviceMemory _allocImageMemory(vk::Image img, vk::MemoryPropertyFlags props)
A helper function for allocating and binding device memory for an image.
abstract base class for simple GLFW windows used to view buffers, etc.
Definition window.hpp:69
SwapChain _swap
buffer-swapping information
Definition window.hpp:320
virtual void cursorPos(double xpos, double ypos)
void enableKeyEvent(bool enable)
void _transitionImageLayout(vk::Image img, vk::Format fmt, vk::ImageLayout oldLayout, vk::ImageLayout newLayout)
A helper function for changing the layout of an image.
Definition window.hpp:509
vk::Queue presentationQ() const
the presentation queue
Definition window.hpp:90
void enableScrollEvent(bool enable)
virtual FrameData * _allocFrameData(Window *w)
virtual function for allocating a FrameData object. Subclasses of the Window class can define a subcl...
vk::Device device() const
return the logical device for this window
Definition window.hpp:84
FrameData * _currentFrame()
get a pointer to the current per-frame rendering state
Definition window.hpp:355
FrameData * _frames[kMaxFrames]
the per-frame rendering state
Definition window.hpp:321
bool _keyEnabled
true when the Key callback is enabled
Definition window.hpp:313
uint32_t _curFrameIdx
index into _frames array for current frame data
Definition window.hpp:322
vk::Rect2D _getScissorsRect()
get the scissors rectangle for this window
Definition window.hpp:434
virtual void key(int key, int scancode, int action, int mods)
virtual void mouseButton(int button, int action, int mods)
vk::SurfaceKHR _surf
the Vulkan surface to render to
Definition window.hpp:319
void _setViewportCmd(vk::CommandBuffer cmdBuf, bool oglView=false)
add a command to set the viewport and scissor to the whole window
Definition window.hpp:451
bool _isVis
true when the window is visible
Definition window.hpp:312
vk::DeviceMemory _allocImageMemory(vk::Image img, vk::MemoryPropertyFlags props)
A helper function for allocating and binding device memory for an image.
Definition window.hpp:487
void show()
Show the window (a no-op if it is already visible)
Definition window.hpp:112
vk::Queue graphicsQ() const
the graphics queue
Definition window.hpp:87
void enableCursorEnterEvent(bool enable)
vk::ImageView _createImageView(vk::Image img, vk::Format fmt, vk::ImageAspectFlags aspectFlags)
A helper function for creating a Vulkan image view object for an image.
Definition window.hpp:498
void _recreateSwapChain()
Recreate the swap chain for this window; this redefines the _swap instance variable and is used when ...
Window(Application *app, CreateWindowInfo const &info)
the Window base-class constructor
FrameData * _nextFrame()
get a pointer to the next per-frame rendering state
Definition window.hpp:368
virtual void _init()
subclasses can override this method to handle any additional initialization that needs to be run afte...
void enableCursorPosEvent(bool enable)
uint32_t _computeQIdx() const
the compute queue index
Definition window.hpp:403
int _ht
window dimensions
Definition window.hpp:311
void _advanceFrame()
advance the current frame
Definition window.hpp:374
bool _scrollEnabled
true when the Scroll callback is enabled
Definition window.hpp:317
bool _cursorEnterEnabled
true when the CursorEnter callback is enabled
Definition window.hpp:315
void setCursorMode(int mode)
bool windowShouldClose()
get the value of the "close" flag for the window
Definition window.hpp:135
virtual void cursorEnter(bool entered)
GLFWwindow * _win
the underlying window
Definition window.hpp:310
SwapChainDetails _getSwapChainDetails()
Get the swap-chain details for a physical device.
bool _mouseButtonEnabled
true when the MouseButton callback is enabled
Definition window.hpp:316
int width() const
the width of the window
Definition window.hpp:521
virtual ~Window()
destructor: it destroys the underlying GLFW window
Application * _app
the owning application
Definition window.hpp:309
bool _cursorPosEnabled
true when the CursorPos callback is enabled
Definition window.hpp:314
vk::Viewport _getViewport(bool oglView=false)
get the natural viewport for the window
Definition window.hpp:410
uint32_t _presentationQIdx() const
the presentation queue
Definition window.hpp:398
Application * app()
return the application pointer
Definition window.hpp:81
void _createSwapChain(bool depth, bool stencil)
Create the swap chain for this window; this initializes the _swap instance variable.
virtual void iconify(bool iconified)
method invoked on Iconify events.
vk::Queue computeQ() const
the compute queue
Definition window.hpp:93
void enableMouseButtonEvent(bool enable)
uint32_t _graphicsQIdx() const
the graphics queue-family index
Definition window.hpp:393
FrameData * _prevFrame()
get a pointer to the previous per-frame rendering state
Definition window.hpp:358
void refresh()
Definition window.hpp:97
void initialize()
virtual void scroll(double xoffset, double yoffset)
void _initAttachments(std::vector< vk::AttachmentDescription > &descs, std::vector< vk::AttachmentReference > &refs)
initialize the attachment descriptors and references for the color and optional depth/stencil-buffer
vk::Result _acquireNextImage()
acquire the next image from the swap chain. This method has the side effect of setting the index of t...
void hide()
Hide the window.
Definition window.hpp:105
virtual void reshape(int wid, int ht)
int height() const
the height of the window
Definition window.hpp:524
virtual void draw()=0
void _setViewportCmd(vk::CommandBuffer cmdBuf, int32_t x, int32_t y, int32_t wid, int32_t ht)
add a viewport command to the command buffer; this also sets the scissor rectangle.
int _wid
Definition window.hpp:311
#define ERROR(msg)
Definition cs237.hpp:60
Definition aabb.hpp:22
constexpr int kMaxFrames
Definition window.hpp:33
T compute
the queue family that supports compute
Definition application.hpp:419
T present
the queue family that supports presentation
Definition application.hpp:418
T graphics
the queue family that supports graphics
Definition application.hpp:417
structure containing parameters for creating windows
Definition window.hpp:37
std::string title
window title
Definition window.hpp:40
int ht
the window height
Definition window.hpp:39
bool depth
do we need depth-buffer support?
Definition window.hpp:42
bool resizable
should the window support resizing
Definition window.hpp:41
bool needsDepthBuf() const
do we need a depth/stencil buffer for the window?
Definition window.hpp:64
CreateWindowInfo(int w, int h)
Definition window.hpp:59
CreateWindowInfo(int w, int h, std::string const &t, bool r, bool d, bool s)
Definition window.hpp:52
int wid
the window width
Definition window.hpp:38
bool stencil
do we need stencil-buffer support?
Definition window.hpp:43
information about the optional depth/stencil buffers for the window
Definition window.hpp:178
vk::ImageView view
image view for depth/image-buffer
Definition window.hpp:184
vk::Image image
depth/image-buffer image
Definition window.hpp:182
bool stencil
true if stencil-buffer is supported
Definition window.hpp:180
vk::Format format
the depth/image-buffer format
Definition window.hpp:181
vk::DeviceMemory imageMem
device memory for depth/image-buffer
Definition window.hpp:183
bool depth
true if depth-buffer is supported
Definition window.hpp:179
A container for the per-frame rendering state.
Definition window.hpp:246
vk::Semaphore imageAvail
Definition window.hpp:250
uint32_t index
Definition window.hpp:256
FrameData(FrameData &)=delete
void waitForFence()
wait for this frame's ‘inFlight’ fence
Definition window.hpp:277
vk::Semaphore finished
Definition window.hpp:252
vk::Fence inFlight
Definition window.hpp:254
Window * win
the owning window
Definition window.hpp:247
vk::CommandBuffer cmdBuf
Definition window.hpp:248
vk::Result present()
present this frame
Definition window.hpp:296
void submitDrawingCommands()
submit drawing commands for this frame using the main command buffer
FrameData(FrameData const &)=delete
FrameData(FrameData &&)=delete
void resetFence()
reset this frame's inFlight fence
Definition window.hpp:286
virtual ~FrameData()
Destructor.
information about swap-chain support
Definition window.hpp:162
vk::SurfaceCapabilitiesKHR capabilities
Definition window.hpp:163
vk::PresentModeKHR choosePresentMode()
choose a presentation mode from the available modes; we prefer "mailbox" (aka triple buffering)
std::vector< vk::SurfaceFormatKHR > formats
Definition window.hpp:164
std::vector< vk::PresentModeKHR > presentModes
Definition window.hpp:165
vk::Extent2D chooseExtent(GLFWwindow *win)
get the extent of the window subject to the limits of the Vulkan device
vk::SurfaceFormatKHR chooseSurfaceFormat()
choose a surface format from the available formats
the collected information about the swap-chain for a window
Definition window.hpp:188
std::vector< vk::ImageView > views
image views for the swap buffers
Definition window.hpp:197
std::vector< vk::Image > images
images for the swap buffers
Definition window.hpp:196
std::optional< vk::ImageView > depthImageView()
get the image view for the depth buffer
Definition window.hpp:226
std::vector< vk::Framebuffer > fBufs
frame buffers
Definition window.hpp:199
int size() const
return the number of buffers in the swap chain
Definition window.hpp:206
bool hasStencilBuffer() const
does the swap-chain support a stencil buffer?
Definition window.hpp:219
void initFramebuffers(vk::RenderPass renderPass)
allocate the frame buffers for the swap chain
std::optional< DepthStencilBuffer > dsBuf
optional depth/stencil-buffer
Definition window.hpp:198
SwapChain(vk::Device dev)
Definition window.hpp:201
bool hasDepthBuffer() const
does the swap-chain support a depth buffer?
Definition window.hpp:213
vk::SwapchainKHR chain
the swap chain object
Definition window.hpp:190
void cleanup()
destroy the Vulkan state for the swap chain
vk::Extent2D extent
size of swap buffer images
Definition window.hpp:192
vk::Format imageFormat
pixel format of image buffers
Definition window.hpp:191
int numAttachments
the number of framebuffer attachments
Definition window.hpp:193
vk::Device device
the owning logical device
Definition window.hpp:189
#define MAX_FRAMES
Definition window.hpp:27