Merge branch 'master' into slang_shaders

This commit is contained in:
Sascha Willems 2025-03-19 21:19:28 +01:00
commit 02559cd99a
16 changed files with 71 additions and 75 deletions

View file

@ -48,7 +48,7 @@ jobs:
build_macOS: build_macOS:
name: Build macOS name: Build macOS
runs-on: macos-13 runs-on: macos-latest
steps: steps:
- uses: actions/checkout@v4 - uses: actions/checkout@v4
with: with:

View file

@ -60,6 +60,11 @@ task copyTask {
include 'metalplate01_rgba.ktx' include 'metalplate01_rgba.ktx'
} }
copy {
from rootProject.ext.assetPath + 'models'
into 'assets/models'
include 'plane_z.gltf'
}
} }

View file

@ -3,7 +3,7 @@
* *
* Platform specific macros for the example main entry points * Platform specific macros for the example main entry points
* *
* Copyright (C) 2024 by Sascha Willems - www.saschawillems.de * Copyright (C) 2024-2025 by Sascha Willems - www.saschawillems.de
* *
* This code is licensed under the MIT license (MIT) (http://opensource.org/licenses/MIT) * This code is licensed under the MIT license (MIT) (http://opensource.org/licenses/MIT)
*/ */
@ -42,12 +42,12 @@ int APIENTRY WinMain(_In_ HINSTANCE hInstance, _In_opt_ HINSTANCE hPrevInstance
VulkanExample *vulkanExample; \ VulkanExample *vulkanExample; \
void android_main(android_app* state) \ void android_main(android_app* state) \
{ \ { \
androidApp = state; \
vks::android::getDeviceConfig(); \
vulkanExample = new VulkanExample(); \ vulkanExample = new VulkanExample(); \
state->userData = vulkanExample; \ state->userData = vulkanExample; \
state->onAppCmd = VulkanExample::handleAppCommand; \ state->onAppCmd = VulkanExample::handleAppCommand; \
state->onInputEvent = VulkanExample::handleAppInput; \ state->onInputEvent = VulkanExample::handleAppInput; \
androidApp = state; \
vks::android::getDeviceConfig(); \
vulkanExample->renderLoop(); \ vulkanExample->renderLoop(); \
delete(vulkanExample); \ delete(vulkanExample); \
} }

View file

@ -1,7 +1,7 @@
/* /*
* Android Vulkan function pointer loader * Android Vulkan function pointer loader
* *
* Copyright (C) 2016-2024 by Sascha Willems - www.saschawillems.de * Copyright (C) 2016-2025 by Sascha Willems - www.saschawillems.de
* *
* This code is licensed under the MIT license (MIT) (http://opensource.org/licenses/MIT) * This code is licensed under the MIT license (MIT) (http://opensource.org/licenses/MIT)
*/ */
@ -359,7 +359,6 @@ namespace vks
jni->DeleteLocalRef(jmessage); jni->DeleteLocalRef(jmessage);
androidApp->activity->vm->DetachCurrentThread(); androidApp->activity->vm->DetachCurrentThread();
return;
} }
} }
} }

View file

@ -1,7 +1,7 @@
/* /*
* Android Vulkan function pointer prototypes * Android Vulkan function pointer prototypes
* *
* Copyright (C) 2016-2024 by Sascha Willems - www.saschawillems.de * Copyright (C) 2016-2025 by Sascha Willems - www.saschawillems.de
* *
* This code is licensed under the MIT license (MIT) (http://opensource.org/licenses/MIT) * This code is licensed under the MIT license (MIT) (http://opensource.org/licenses/MIT)
*/ */
@ -29,16 +29,6 @@
#include <memory> #include <memory>
#include <string> #include <string>
// Missing from the NDK
namespace std
{
template<typename T, typename... Args>
std::unique_ptr<T> make_unique(Args&&... args)
{
return std::unique_ptr<T>(new T(std::forward<Args>(args)...));
}
}
// Global reference to android application object // Global reference to android application object
extern android_app* androidApp; extern android_app* androidApp;

View file

@ -76,7 +76,7 @@ VkResult VulkanExampleBase::createInstance()
#endif #endif
// Enabled requested instance extensions // Enabled requested instance extensions
if (enabledInstanceExtensions.size() > 0) if (!enabledInstanceExtensions.empty())
{ {
for (const char * enabledExtension : enabledInstanceExtensions) for (const char * enabledExtension : enabledInstanceExtensions)
{ {
@ -120,7 +120,7 @@ VkResult VulkanExampleBase::createInstance()
instanceExtensions.push_back(VK_EXT_DEBUG_UTILS_EXTENSION_NAME); instanceExtensions.push_back(VK_EXT_DEBUG_UTILS_EXTENSION_NAME);
} }
if (instanceExtensions.size() > 0) { if (!instanceExtensions.empty()) {
instanceCreateInfo.enabledExtensionCount = (uint32_t)instanceExtensions.size(); instanceCreateInfo.enabledExtensionCount = (uint32_t)instanceExtensions.size();
instanceCreateInfo.ppEnabledExtensionNames = instanceExtensions.data(); instanceCreateInfo.ppEnabledExtensionNames = instanceExtensions.data();
} }
@ -316,7 +316,7 @@ void VulkanExampleBase::renderLoop()
benchmark.run([=] { render(); }, vulkanDevice->properties); benchmark.run([=] { render(); }, vulkanDevice->properties);
vkDeviceWaitIdle(device); vkDeviceWaitIdle(device);
if (benchmark.filename != "") { if (!benchmark.filename.empty()) {
benchmark.saveResults(); benchmark.saveResults();
} }
return; return;
@ -344,7 +344,7 @@ void VulkanExampleBase::renderLoop()
} }
} }
#elif defined(VK_USE_PLATFORM_ANDROID_KHR) #elif defined(VK_USE_PLATFORM_ANDROID_KHR)
while (1) while (true)
{ {
int ident; int ident;
int events; int events;
@ -353,9 +353,9 @@ void VulkanExampleBase::renderLoop()
focused = true; focused = true;
while ((ident = ALooper_pollOnce(focused ? 0 : -1, NULL, &events, (void**)&source)) > ALOOPER_POLL_TIMEOUT) while ((ident = ALooper_pollOnce(focused ? 0 : -1, nullptr, &events, (void**)&source)) > ALOOPER_POLL_TIMEOUT)
{ {
if (source != NULL) if (source != nullptr)
{ {
source->process(androidApp, source); source->process(androidApp, source);
} }
@ -404,8 +404,6 @@ void VulkanExampleBase::renderLoop()
updateOverlay(); updateOverlay();
bool updateView = false;
// Check touch state (for movement) // Check touch state (for movement)
if (touchDown) { if (touchDown) {
touchTimer += frameTimer; touchTimer += frameTimer;
@ -422,23 +420,20 @@ void VulkanExampleBase::renderLoop()
if (std::abs(gamePadState.axisLeft.x) > deadZone) if (std::abs(gamePadState.axisLeft.x) > deadZone)
{ {
camera.rotate(glm::vec3(0.0f, gamePadState.axisLeft.x * 0.5f, 0.0f)); camera.rotate(glm::vec3(0.0f, gamePadState.axisLeft.x * 0.5f, 0.0f));
updateView = true;
} }
if (std::abs(gamePadState.axisLeft.y) > deadZone) if (std::abs(gamePadState.axisLeft.y) > deadZone)
{ {
camera.rotate(glm::vec3(gamePadState.axisLeft.y * 0.5f, 0.0f, 0.0f)); camera.rotate(glm::vec3(gamePadState.axisLeft.y * 0.5f, 0.0f, 0.0f));
updateView = true;
} }
// Zoom // Zoom
if (std::abs(gamePadState.axisRight.y) > deadZone) if (std::abs(gamePadState.axisRight.y) > deadZone)
{ {
camera.translate(glm::vec3(0.0f, 0.0f, gamePadState.axisRight.y * 0.01f)); camera.translate(glm::vec3(0.0f, 0.0f, gamePadState.axisRight.y * 0.01f));
updateView = true;
} }
} }
else else
{ {
updateView = camera.updatePad(gamePadState.axisLeft, gamePadState.axisRight, frameTimer); camera.updatePad(gamePadState.axisLeft, gamePadState.axisRight, frameTimer);
} }
} }
} }
@ -915,9 +910,9 @@ VulkanExampleBase::~VulkanExampleBase()
{ {
vkDestroyRenderPass(device, renderPass, nullptr); vkDestroyRenderPass(device, renderPass, nullptr);
} }
for (uint32_t i = 0; i < frameBuffers.size(); i++) for (auto& frameBuffer : frameBuffers)
{ {
vkDestroyFramebuffer(device, frameBuffers[i], nullptr); vkDestroyFramebuffer(device, frameBuffer, nullptr);
} }
for (auto& shaderModule : shaderModules) for (auto& shaderModule : shaderModules)
@ -1509,7 +1504,6 @@ int32_t VulkanExampleBase::handleAppInput(struct android_app* app, AInputEvent*
{ {
int32_t keyCode = AKeyEvent_getKeyCode((const AInputEvent*)event); int32_t keyCode = AKeyEvent_getKeyCode((const AInputEvent*)event);
int32_t action = AKeyEvent_getAction((const AInputEvent*)event); int32_t action = AKeyEvent_getAction((const AInputEvent*)event);
int32_t button = 0;
if (action == AKEY_EVENT_ACTION_UP) if (action == AKEY_EVENT_ACTION_UP)
return 0; return 0;
@ -1554,7 +1548,7 @@ int32_t VulkanExampleBase::handleAppInput(struct android_app* app, AInputEvent*
void VulkanExampleBase::handleAppCommand(android_app * app, int32_t cmd) void VulkanExampleBase::handleAppCommand(android_app * app, int32_t cmd)
{ {
assert(app->userData != NULL); assert(app->userData != nullptr);
VulkanExampleBase* vulkanExample = reinterpret_cast<VulkanExampleBase*>(app->userData); VulkanExampleBase* vulkanExample = reinterpret_cast<VulkanExampleBase*>(app->userData);
switch (cmd) switch (cmd)
{ {
@ -1568,7 +1562,7 @@ void VulkanExampleBase::handleAppCommand(android_app * app, int32_t cmd)
break; break;
case APP_CMD_INIT_WINDOW: case APP_CMD_INIT_WINDOW:
LOGD("APP_CMD_INIT_WINDOW"); LOGD("APP_CMD_INIT_WINDOW");
if (androidApp->window != NULL) if (androidApp->window != nullptr)
{ {
if (vulkanExample->initVulkan()) { if (vulkanExample->initVulkan()) {
vulkanExample->prepare(); vulkanExample->prepare();
@ -3195,8 +3189,8 @@ void VulkanExampleBase::windowResize()
vkDestroyImage(device, depthStencil.image, nullptr); vkDestroyImage(device, depthStencil.image, nullptr);
vkFreeMemory(device, depthStencil.memory, nullptr); vkFreeMemory(device, depthStencil.memory, nullptr);
setupDepthStencil(); setupDepthStencil();
for (uint32_t i = 0; i < frameBuffers.size(); i++) { for (auto& frameBuffer : frameBuffers) {
vkDestroyFramebuffer(device, frameBuffers[i], nullptr); vkDestroyFramebuffer(device, frameBuffer, nullptr);
} }
setupFrameBuffer(); setupFrameBuffer();

View file

@ -77,8 +77,8 @@ class VulkanExampleBase
{ {
private: private:
std::string getWindowTitle() const; std::string getWindowTitle() const;
uint32_t destWidth; uint32_t destWidth{};
uint32_t destHeight; uint32_t destHeight{};
bool resizing = false; bool resizing = false;
void handleMouseMove(int32_t x, int32_t y); void handleMouseMove(int32_t x, int32_t y);
void nextFrame(); void nextFrame();
@ -122,13 +122,13 @@ protected:
// Handle to the device graphics queue that command buffers are submitted to // Handle to the device graphics queue that command buffers are submitted to
VkQueue queue{ VK_NULL_HANDLE }; VkQueue queue{ VK_NULL_HANDLE };
// Depth buffer format (selected during Vulkan initialization) // Depth buffer format (selected during Vulkan initialization)
VkFormat depthFormat; VkFormat depthFormat{VK_FORMAT_UNDEFINED};
// Command buffer pool // Command buffer pool
VkCommandPool cmdPool{ VK_NULL_HANDLE }; VkCommandPool cmdPool{ VK_NULL_HANDLE };
/** @brief Pipeline stages used to wait at for graphics queue submissions */ /** @brief Pipeline stages used to wait at for graphics queue submissions */
VkPipelineStageFlags submitPipelineStages = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT; VkPipelineStageFlags submitPipelineStages = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT;
// Contains command buffers and semaphores to be presented to the queue // Contains command buffers and semaphores to be presented to the queue
VkSubmitInfo submitInfo; VkSubmitInfo submitInfo{};
// Command buffers used for rendering // Command buffers used for rendering
std::vector<VkCommandBuffer> drawCmdBuffers; std::vector<VkCommandBuffer> drawCmdBuffers;
// Global render pass for frame buffer writes // Global render pass for frame buffer writes
@ -151,7 +151,7 @@ protected:
VkSemaphore presentComplete; VkSemaphore presentComplete;
// Command buffer submission and execution // Command buffer submission and execution
VkSemaphore renderComplete; VkSemaphore renderComplete;
} semaphores; } semaphores{};
std::vector<VkFence> waitFences; std::vector<VkFence> waitFences;
bool requiresStencil{ false }; bool requiresStencil{ false };
public: public:
@ -170,7 +170,7 @@ public:
vks::Benchmark benchmark; vks::Benchmark benchmark;
/** @brief Encapsulated physical and logical vulkan device */ /** @brief Encapsulated physical and logical vulkan device */
vks::VulkanDevice *vulkanDevice; vks::VulkanDevice *vulkanDevice{};
/** @brief Example settings that can be changed e.g. by command line arguments */ /** @brief Example settings that can be changed e.g. by command line arguments */
struct Settings { struct Settings {
@ -234,7 +234,7 @@ public:
struct TouchPos { struct TouchPos {
int32_t x; int32_t x;
int32_t y; int32_t y;
} touchPos; } touchPos{};
bool touchDown = false; bool touchDown = false;
double touchTimer = 0.0; double touchTimer = 0.0;
int64_t lastTapTime = 0; int64_t lastTapTime = 0;

View file

@ -40,7 +40,6 @@ public:
VkDeviceMemory memory{ VK_NULL_HANDLE }; VkDeviceMemory memory{ VK_NULL_HANDLE };
}; };
Image renderImage; Image renderImage;
Image depthStencilRenderImage;
VulkanExample() : VulkanExampleBase() VulkanExample() : VulkanExampleBase()
{ {
@ -67,7 +66,7 @@ public:
deviceCreatepNextChain = &enabledDynamicRenderingFeaturesKHR; deviceCreatepNextChain = &enabledDynamicRenderingFeaturesKHR;
} }
~VulkanExample() ~VulkanExample() override
{ {
if (device) { if (device) {
vkDestroyPipeline(device, pipeline, nullptr); vkDestroyPipeline(device, pipeline, nullptr);
@ -160,7 +159,7 @@ public:
} }
// Enable physical device features required for this example // Enable physical device features required for this example
virtual void getEnabledFeatures() void getEnabledFeatures() override
{ {
// Enable anisotropic filtering if supported // Enable anisotropic filtering if supported
if (deviceFeatures.samplerAnisotropy) { if (deviceFeatures.samplerAnisotropy) {
@ -174,7 +173,7 @@ public:
model.loadFromFile(getAssetPath() + "models/voyager.gltf", vulkanDevice, queue, glTFLoadingFlags); model.loadFromFile(getAssetPath() + "models/voyager.gltf", vulkanDevice, queue, glTFLoadingFlags);
} }
void buildCommandBuffers() void buildCommandBuffers() override
{ {
VkCommandBufferBeginInfo cmdBufInfo = vks::initializers::commandBufferBeginInfo(); VkCommandBufferBeginInfo cmdBufInfo = vks::initializers::commandBufferBeginInfo();
@ -365,7 +364,7 @@ public:
memcpy(uniformBuffer.mapped, &uniformData, sizeof(uniformData)); memcpy(uniformBuffer.mapped, &uniformData, sizeof(uniformData));
} }
void prepare() void prepare() override
{ {
VulkanExampleBase::prepare(); VulkanExampleBase::prepare();
@ -390,7 +389,7 @@ public:
VulkanExampleBase::submitFrame(); VulkanExampleBase::submitFrame();
} }
virtual void render() void render() override
{ {
if (!prepared) if (!prepared)
return; return;

View file

@ -70,7 +70,7 @@ public:
deviceCreatepNextChain = &enabledPhysicalDeviceHostImageCopyFeaturesEXT; deviceCreatepNextChain = &enabledPhysicalDeviceHostImageCopyFeaturesEXT;
} }
~VulkanExample() ~VulkanExample() override
{ {
if (device) { if (device) {
destroyTextureImage(texture); destroyTextureImage(texture);
@ -82,7 +82,7 @@ public:
} }
// Enable physical device features required for this example // Enable physical device features required for this example
virtual void getEnabledFeatures() void getEnabledFeatures() override
{ {
// Enable anisotropic filtering if supported // Enable anisotropic filtering if supported
if (deviceFeatures.samplerAnisotropy) { if (deviceFeatures.samplerAnisotropy) {
@ -134,7 +134,6 @@ public:
texture.height = ktxTexture->baseHeight; texture.height = ktxTexture->baseHeight;
texture.mipLevels = ktxTexture->numLevels; texture.mipLevels = ktxTexture->numLevels;
ktx_uint8_t *ktxTextureData = ktxTexture_GetData(ktxTexture); ktx_uint8_t *ktxTextureData = ktxTexture_GetData(ktxTexture);
ktx_size_t ktxTextureSize = ktxTexture_GetSize(ktxTexture);
const VkFormat imageFormat = VK_FORMAT_R8G8B8A8_UNORM; const VkFormat imageFormat = VK_FORMAT_R8G8B8A8_UNORM;
@ -271,7 +270,7 @@ public:
vkFreeMemory(device, texture.deviceMemory, nullptr); vkFreeMemory(device, texture.deviceMemory, nullptr);
} }
void buildCommandBuffers() void buildCommandBuffers() override
{ {
VkCommandBufferBeginInfo cmdBufInfo = vks::initializers::commandBufferBeginInfo(); VkCommandBufferBeginInfo cmdBufInfo = vks::initializers::commandBufferBeginInfo();
@ -371,11 +370,11 @@ public:
VkPipelineMultisampleStateCreateInfo multisampleState = vks::initializers::pipelineMultisampleStateCreateInfo(VK_SAMPLE_COUNT_1_BIT, 0); VkPipelineMultisampleStateCreateInfo multisampleState = vks::initializers::pipelineMultisampleStateCreateInfo(VK_SAMPLE_COUNT_1_BIT, 0);
std::vector<VkDynamicState> dynamicStateEnables = { VK_DYNAMIC_STATE_VIEWPORT, VK_DYNAMIC_STATE_SCISSOR }; std::vector<VkDynamicState> dynamicStateEnables = { VK_DYNAMIC_STATE_VIEWPORT, VK_DYNAMIC_STATE_SCISSOR };
VkPipelineDynamicStateCreateInfo dynamicState = vks::initializers::pipelineDynamicStateCreateInfo(dynamicStateEnables); VkPipelineDynamicStateCreateInfo dynamicState = vks::initializers::pipelineDynamicStateCreateInfo(dynamicStateEnables);
std::array<VkPipelineShaderStageCreateInfo,2> shaderStages; // Shaders
std::array<VkPipelineShaderStageCreateInfo,2> shaderStages = {
// Shaders loadShader(getShadersPath() + "texture/texture.vert.spv", VK_SHADER_STAGE_VERTEX_BIT),
shaderStages[0] = loadShader(getShadersPath() + "texture/texture.vert.spv", VK_SHADER_STAGE_VERTEX_BIT); loadShader(getShadersPath() + "texture/texture.frag.spv", VK_SHADER_STAGE_FRAGMENT_BIT)
shaderStages[1] = loadShader(getShadersPath() + "texture/texture.frag.spv", VK_SHADER_STAGE_FRAGMENT_BIT); };
VkGraphicsPipelineCreateInfo pipelineCreateInfo = vks::initializers::pipelineCreateInfo(pipelineLayout, renderPass, 0); VkGraphicsPipelineCreateInfo pipelineCreateInfo = vks::initializers::pipelineCreateInfo(pipelineLayout, renderPass, 0);
pipelineCreateInfo.pInputAssemblyState = &inputAssemblyState; pipelineCreateInfo.pInputAssemblyState = &inputAssemblyState;
@ -413,14 +412,14 @@ public:
plane.loadFromFile(getAssetPath() + "models/plane_z.gltf", vulkanDevice, queue, glTFLoadingFlags); plane.loadFromFile(getAssetPath() + "models/plane_z.gltf", vulkanDevice, queue, glTFLoadingFlags);
} }
void prepare() void prepare() override
{ {
VulkanExampleBase::prepare(); VulkanExampleBase::prepare();
// Get the function pointers required host image copies // Get the function pointers required host image copies
vkCopyMemoryToImageEXT = reinterpret_cast<PFN_vkCopyMemoryToImageEXT>(vkGetDeviceProcAddr(device, "vkCopyMemoryToImageEXT")); vkCopyMemoryToImageEXT = reinterpret_cast<PFN_vkCopyMemoryToImageEXT>(vkGetDeviceProcAddr(device, "vkCopyMemoryToImageEXT"));
vkTransitionImageLayoutEXT = reinterpret_cast<PFN_vkTransitionImageLayoutEXT>(vkGetDeviceProcAddr(device, "vkTransitionImageLayoutEXT")); vkTransitionImageLayoutEXT = reinterpret_cast<PFN_vkTransitionImageLayoutEXT>(vkGetDeviceProcAddr(device, "vkTransitionImageLayoutEXT"));
vkGetPhysicalDeviceFormatProperties2 = reinterpret_cast<PFN_vkGetPhysicalDeviceFormatProperties2>(vkGetInstanceProcAddr(instance, "vkGetPhysicalDeviceFormatProperties2")); vkGetPhysicalDeviceFormatProperties2 = reinterpret_cast<PFN_vkGetPhysicalDeviceFormatProperties2>(vkGetInstanceProcAddr(instance, "vkGetPhysicalDeviceFormatProperties2KHR"));
loadAssets(); loadAssets();
loadTexture(); loadTexture();
@ -440,7 +439,7 @@ public:
VulkanExampleBase::submitFrame(); VulkanExampleBase::submitFrame();
} }
virtual void render() void render() override
{ {
if (!prepared) if (!prepared)
return; return;
@ -448,7 +447,7 @@ public:
draw(); draw();
} }
virtual void OnUpdateUIOverlay(vks::UIOverlay *overlay) void OnUpdateUIOverlay(vks::UIOverlay *overlay) override
{ {
if (overlay->header("Settings")) { if (overlay->header("Settings")) {
if (overlay->sliderFloat("LOD bias", &uniformData.lodBias, 0.0f, (float)texture.mipLevels)) { if (overlay->sliderFloat("LOD bias", &uniformData.lodBias, 0.0f, (float)texture.mipLevels)) {

View file

@ -99,6 +99,8 @@ public:
camera.setRotation(glm::vec3(0.5f, 210.05f, 0.0f)); camera.setRotation(glm::vec3(0.5f, 210.05f, 0.0f));
camera.setPerspective(60.0f, (float)width / (float)height, 0.1f, 256.0f); camera.setPerspective(60.0f, (float)width / (float)height, 0.1f, 256.0f);
ui.subpass = 2; ui.subpass = 2;
enabledFeatures.fragmentStoresAndAtomics = VK_TRUE;
} }
~VulkanExample() ~VulkanExample()

View file

@ -6,7 +6,7 @@
* Contrary to the other examples, this one won't make use of helper functions or initializers * Contrary to the other examples, this one won't make use of helper functions or initializers
* Except in a few cases (swap chain setup e.g.) * Except in a few cases (swap chain setup e.g.)
* *
* Copyright (C) 2016-2024 by Sascha Willems - www.saschawillems.de * Copyright (C) 2016-2025 by Sascha Willems - www.saschawillems.de
* *
* This code is licensed under the MIT license (MIT) (http://opensource.org/licenses/MIT) * This code is licensed under the MIT license (MIT) (http://opensource.org/licenses/MIT)
*/ */
@ -126,7 +126,7 @@ public:
// Values not set here are initialized in the base class constructor // Values not set here are initialized in the base class constructor
} }
~VulkanExample() ~VulkanExample() override
{ {
// Clean up used Vulkan resources // Clean up used Vulkan resources
// Note: Inherited destructor cleans up resources stored in base class // Note: Inherited destructor cleans up resources stored in base class
@ -452,7 +452,7 @@ public:
// Create the depth (and stencil) buffer attachments used by our framebuffers // Create the depth (and stencil) buffer attachments used by our framebuffers
// Note: Override of virtual function in the base class and called from within VulkanExampleBase::prepare // Note: Override of virtual function in the base class and called from within VulkanExampleBase::prepare
void setupDepthStencil() void setupDepthStencil() override
{ {
// Create an optimal image used as the depth stencil attachment // Create an optimal image used as the depth stencil attachment
VkImageCreateInfo imageCI{}; VkImageCreateInfo imageCI{};
@ -502,7 +502,7 @@ public:
// Create a frame buffer for each swap chain image // Create a frame buffer for each swap chain image
// Note: Override of virtual function in the base class and called from within VulkanExampleBase::prepare // Note: Override of virtual function in the base class and called from within VulkanExampleBase::prepare
void setupFrameBuffer() void setupFrameBuffer() override
{ {
// Create a frame buffer for every image in the swapchain // Create a frame buffer for every image in the swapchain
frameBuffers.resize(swapChain.images.size()); frameBuffers.resize(swapChain.images.size());
@ -533,7 +533,7 @@ public:
// This allows the driver to know up-front what the rendering will look like and is a good opportunity to optimize especially on tile-based renderers (with multiple subpasses) // This allows the driver to know up-front what the rendering will look like and is a good opportunity to optimize especially on tile-based renderers (with multiple subpasses)
// Using sub pass dependencies also adds implicit layout transitions for the attachment used, so we don't need to add explicit image memory barriers to transform them // Using sub pass dependencies also adds implicit layout transitions for the attachment used, so we don't need to add explicit image memory barriers to transform them
// Note: Override of virtual function in the base class and called from within VulkanExampleBase::prepare // Note: Override of virtual function in the base class and called from within VulkanExampleBase::prepare
void setupRenderPass() void setupRenderPass() override
{ {
// This example will use a single render pass with one subpass // This example will use a single render pass with one subpass
@ -622,7 +622,7 @@ public:
// Vulkan loads its shaders from an immediate binary representation called SPIR-V // Vulkan loads its shaders from an immediate binary representation called SPIR-V
// Shaders are compiled offline from e.g. GLSL using the reference glslang compiler // Shaders are compiled offline from e.g. GLSL using the reference glslang compiler
// This function loads such a shader from a binary file and returns a shader module structure // This function loads such a shader from a binary file and returns a shader module structure
VkShaderModule loadSPIRVShader(std::string filename) VkShaderModule loadSPIRVShader(const std::string& filename)
{ {
size_t shaderSize; size_t shaderSize;
char* shaderCode{ nullptr }; char* shaderCode{ nullptr };
@ -886,7 +886,7 @@ public:
} }
void prepare() void prepare() override
{ {
VulkanExampleBase::prepare(); VulkanExampleBase::prepare();
createSynchronizationPrimitives(); createSynchronizationPrimitives();
@ -900,7 +900,7 @@ public:
prepared = true; prepared = true;
} }
virtual void render() void render() override
{ {
if (!prepared) if (!prepared)
return; return;

View file

@ -117,7 +117,7 @@ public:
deviceCreatepNextChain = &enabledFeatures; deviceCreatepNextChain = &enabledFeatures;
} }
~VulkanExample() ~VulkanExample() override
{ {
// Clean up used Vulkan resources // Clean up used Vulkan resources
// Note: Inherited destructor cleans up resources stored in base class // Note: Inherited destructor cleans up resources stored in base class
@ -140,6 +140,14 @@ public:
} }
} }
virtual void getEnabledFeatures() override
{
// Vulkan 1.3 device support is required for this example
if (deviceProperties.apiVersion < VK_API_VERSION_1_3) {
vks::tools::exitFatal("Selected GPU does not support support Vulkan 1.3", VK_ERROR_INCOMPATIBLE_DRIVER);
}
}
// This function is used to request a device memory type that supports all the property flags we request (e.g. device local, host visible) // This function is used to request a device memory type that supports all the property flags we request (e.g. device local, host visible)
// Upon success it will return the index of the memory type that fits our requested memory properties // Upon success it will return the index of the memory type that fits our requested memory properties
// This is necessary as implementations can offer an arbitrary number of memory types with different memory properties // This is necessary as implementations can offer an arbitrary number of memory types with different memory properties
@ -381,7 +389,7 @@ public:
// Create the depth (and stencil) buffer attachments // Create the depth (and stencil) buffer attachments
// While we don't do any depth testing in this sample, having depth testing is very common so it's a good idea to learn it from the very start // While we don't do any depth testing in this sample, having depth testing is very common so it's a good idea to learn it from the very start
void setupDepthStencil() void setupDepthStencil() override
{ {
// Create an optimal tiled image used as the depth stencil attachment // Create an optimal tiled image used as the depth stencil attachment
VkImageCreateInfo imageCI{ VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO }; VkImageCreateInfo imageCI{ VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO };
@ -428,7 +436,7 @@ public:
// Vulkan loads its shaders from an immediate binary representation called SPIR-V // Vulkan loads its shaders from an immediate binary representation called SPIR-V
// Shaders are compiled offline from e.g. GLSL using the reference glslang compiler // Shaders are compiled offline from e.g. GLSL using the reference glslang compiler
// This function loads such a shader from a binary file and returns a shader module structure // This function loads such a shader from a binary file and returns a shader module structure
VkShaderModule loadSPIRVShader(std::string filename) VkShaderModule loadSPIRVShader(const std::string& filename)
{ {
size_t shaderSize; size_t shaderSize;
char* shaderCode{ nullptr }; char* shaderCode{ nullptr };
@ -661,7 +669,7 @@ public:
} }
void prepare() void prepare() override
{ {
VulkanExampleBase::prepare(); VulkanExampleBase::prepare();
createSynchronizationPrimitives(); createSynchronizationPrimitives();
@ -673,7 +681,7 @@ public:
prepared = true; prepared = true;
} }
virtual void render() override void render() override
{ {
// Use a fence to wait until the command buffer has finished execution before using it again // Use a fence to wait until the command buffer has finished execution before using it again
vkWaitForFences(device, 1, &waitFences[currentFrame], VK_TRUE, UINT64_MAX); vkWaitForFences(device, 1, &waitFences[currentFrame], VK_TRUE, UINT64_MAX);