Skip to content

Commit

Permalink
wip: move from validation features to layer settings
Browse files Browse the repository at this point in the history
  • Loading branch information
knokko committed Nov 23, 2024
1 parent a808a3a commit fdaa6f2
Show file tree
Hide file tree
Showing 8 changed files with 150 additions and 30 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

import com.github.knokko.boiler.builders.BoilerBuilder;
import com.github.knokko.boiler.builders.WindowBuilder;
import com.github.knokko.boiler.builders.instance.VendorBestPractices;
import com.github.knokko.boiler.commands.CommandRecorder;
import com.github.knokko.boiler.pipelines.GraphicsPipelineBuilder;
import com.github.knokko.boiler.pipelines.ShaderInfo;
Expand All @@ -26,11 +27,27 @@ public static void main(String[] args) throws InterruptedException {
VK_API_VERSION_1_0, "HelloTriangle", VK_MAKE_VERSION(0, 1, 0)
)
.validation().forbidValidationErrors()
.bestPractices(new VendorBestPractices(true, true, true, true))
.addWindow(new WindowBuilder(
1000, 800, VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT
).presentModes(VK_PRESENT_MODE_FIFO_KHR, VK_PRESENT_MODE_MAILBOX_KHR))
.build();

try (var stack = stackPush()) {
var allocateInfo = VkMemoryAllocateInfo.calloc(stack);
allocateInfo.sType$Default();
allocateInfo.allocationSize(12345);
allocateInfo.memoryTypeIndex(2);

var pMemory = stack.callocLong(1);
for (int counter = 0; counter < 1000; counter++) {
assertVkSuccess(vkAllocateMemory(
boiler.vkDevice(), allocateInfo, null, pMemory
), "AllocateMemory", "trigger-nvidia-warnings");

vkFreeMemory(boiler.vkDevice(), pMemory.get(0), null);
}
}
int numFramesInFlight = 3;
var commandPool = boiler.commands.createPool(
VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT | VK_COMMAND_POOL_CREATE_TRANSIENT_BIT,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ public static void main(String[] args) throws InterruptedException {
VK_API_VERSION_1_1, "SimpleRingApproximation", VK_MAKE_VERSION(0, 2, 0)
)
.validation(new ValidationFeatures(false, false, false, true, true))
.bestPractices()
.enableDynamicRendering()
.addWindow(new WindowBuilder(1000, 8000, VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT))
.build();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@
import com.github.knokko.boiler.buffers.MappedVkbBuffer;
import com.github.knokko.boiler.builders.BoilerBuilder;
import com.github.knokko.boiler.builders.WindowBuilder;
import com.github.knokko.boiler.builders.instance.ValidationFeatures;
import com.github.knokko.boiler.commands.CommandRecorder;
import com.github.knokko.boiler.culling.FrustumCuller;
import com.github.knokko.boiler.descriptors.VkbDescriptorSetLayout;
Expand Down Expand Up @@ -303,8 +302,7 @@ public static void main(String[] args) throws InterruptedException {
var boiler = new BoilerBuilder(
VK_API_VERSION_1_2, "TerrainPlayground", VK_MAKE_VERSION(0, 1, 0)
)
.validation(new ValidationFeatures(true, true, false, true, true))
.forbidValidationErrors()
.validation().forbidValidationErrors().bestPractices()
.addWindow(new WindowBuilder(1000, 800, VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT))
.requiredFeatures12(VkPhysicalDeviceVulkan12Features::timelineSemaphore)
.featurePicker12((stack, supported, toEnable) -> toEnable.timelineSemaphore(true))
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,7 @@ public static void main(String[] args) throws InterruptedException {
.validation(new ValidationFeatures(
false, false, false, true, true
))
.bestPractices()
.dontInitGLFW()
.addWindow(new WindowBuilder(
800, 600, VK_IMAGE_USAGE_TRANSFER_DST_BIT
Expand Down
22 changes: 20 additions & 2 deletions src/main/java/com/github/knokko/boiler/builders/BoilerBuilder.java
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
import com.github.knokko.boiler.builders.device.*;
import com.github.knokko.boiler.builders.instance.PreVkInstanceCreator;
import com.github.knokko.boiler.builders.instance.ValidationFeatures;
import com.github.knokko.boiler.builders.instance.VendorBestPractices;
import com.github.knokko.boiler.builders.instance.VkInstanceCreator;
import com.github.knokko.boiler.builders.queue.MinimalQueueFamilyMapper;
import com.github.knokko.boiler.builders.queue.QueueFamilyMapper;
Expand All @@ -25,10 +26,10 @@
import static org.lwjgl.system.MemoryStack.stackPush;
import static org.lwjgl.system.MemoryUtil.memUTF8;
import static org.lwjgl.vulkan.EXTDebugUtils.*;
import static org.lwjgl.vulkan.EXTLayerSettings.VK_EXT_LAYER_SETTINGS_EXTENSION_NAME;
import static org.lwjgl.vulkan.EXTMemoryBudget.VK_EXT_MEMORY_BUDGET_EXTENSION_NAME;
import static org.lwjgl.vulkan.EXTSurfaceMaintenance1.VK_EXT_SURFACE_MAINTENANCE_1_EXTENSION_NAME;
import static org.lwjgl.vulkan.EXTSwapchainMaintenance1.VK_EXT_SWAPCHAIN_MAINTENANCE_1_EXTENSION_NAME;
import static org.lwjgl.vulkan.EXTValidationFeatures.*;
import static org.lwjgl.vulkan.KHRBindMemory2.VK_KHR_BIND_MEMORY_2_EXTENSION_NAME;
import static org.lwjgl.vulkan.KHRCreateRenderpass2.VK_KHR_CREATE_RENDERPASS_2_EXTENSION_NAME;
import static org.lwjgl.vulkan.KHRDedicatedAllocation.VK_KHR_DEDICATED_ALLOCATION_EXTENSION_NAME;
Expand Down Expand Up @@ -86,6 +87,7 @@ public class BoilerBuilder {
final Set<String> requiredVulkanDeviceExtensions = new HashSet<>();

ValidationFeatures validationFeatures = null;
VendorBestPractices vendorBestPractices = null;
boolean forbidValidationErrors = false;

boolean dynamicRendering = false;
Expand Down Expand Up @@ -176,6 +178,22 @@ public BoilerBuilder validation() {
}
}

/**
* Enables vendor-specific best practices. This will only work if validation is enabled, does nothing otherwise.
*/
public BoilerBuilder bestPractices(VendorBestPractices bestPractices) {
this.vendorBestPractices = bestPractices;
return this;
} // TODO Document this and test this

/**
* Enables AMD best practices and Nvidia best practices. This will only work if validation is enabled, does
* nothing otherwise.
*/
public BoilerBuilder bestPractices() {
return bestPractices(new VendorBestPractices(false, true, false, true));
}

/**
* Ensures that a <i>ValidationException</i> will be thrown whenever a validation error is encountered, which is
* nice for tracing the function call that caused it, as well as unit testing.<br>
Expand Down Expand Up @@ -590,7 +608,7 @@ public BoilerInstance build() throws GLFWFailureException, VulkanFailureExceptio

if (validationFeatures != null) {
this.requiredVulkanInstanceExtensions.add(VK_EXT_DEBUG_UTILS_EXTENSION_NAME);
this.requiredVulkanInstanceExtensions.add(VK_EXT_VALIDATION_FEATURES_EXTENSION_NAME);
this.requiredVulkanInstanceExtensions.add(VK_EXT_LAYER_SETTINGS_EXTENSION_NAME);
this.requiredVulkanLayers.add("VK_LAYER_KHRONOS_validation");
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,16 +6,19 @@
import com.github.knokko.boiler.utilities.CollectionHelper;
import org.lwjgl.vulkan.*;

import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Set;

import static com.github.knokko.boiler.exceptions.VulkanFailureException.assertVkSuccess;
import static org.lwjgl.system.MemoryStack.stackPush;
import static org.lwjgl.vulkan.EXTValidationFeatures.*;
import static org.lwjgl.system.MemoryUtil.*;
import static org.lwjgl.vulkan.EXTLayerSettings.VK_LAYER_SETTING_TYPE_BOOL32_EXT;
import static org.lwjgl.vulkan.EXTLayerSettings.VK_LAYER_SETTING_TYPE_INT32_EXT;
import static org.lwjgl.vulkan.KHRPortabilityEnumeration.VK_INSTANCE_CREATE_ENUMERATE_PORTABILITY_BIT_KHR;
import static org.lwjgl.vulkan.KHRPortabilityEnumeration.VK_KHR_PORTABILITY_ENUMERATION_EXTENSION_NAME;
import static org.lwjgl.vulkan.VK10.vkEnumerateInstanceExtensionProperties;
import static org.lwjgl.vulkan.VK10.vkEnumerateInstanceLayerProperties;
import static org.lwjgl.vulkan.VK10.*;

class BoilerInstanceBuilder {

Expand Down Expand Up @@ -88,38 +91,63 @@ static Result createInstance(BoilerBuilder builder) {
appInfo.engineVersion(builder.engineVersion);
appInfo.apiVersion(builder.apiVersion);

VkValidationFeaturesEXT pValidationFeatures;
VkLayerSettingsCreateInfoEXT ciValidationSettings;
if (builder.validationFeatures != null) {

pValidationFeatures = VkValidationFeaturesEXT.calloc(stack);
pValidationFeatures.sType$Default();
pValidationFeatures.pNext(0L);
ciValidationSettings = VkLayerSettingsCreateInfoEXT.calloc(stack);
ciValidationSettings.sType$Default();

var supportedValidationFeatures = new ValidationFeaturesChecker(stack);

var validationFlags = stack.callocInt(5);
if (builder.validationFeatures.gpuAssisted() && supportedValidationFeatures.gpuAssistedValidation)
validationFlags.put(VK_VALIDATION_FEATURE_ENABLE_GPU_ASSISTED_EXT);
if (builder.validationFeatures.gpuAssistedReserve() && supportedValidationFeatures.gpuAssistedValidation)
validationFlags.put(VK_VALIDATION_FEATURE_ENABLE_GPU_ASSISTED_RESERVE_BINDING_SLOT_EXT);
if (builder.validationFeatures.bestPractices())
validationFlags.put(VK_VALIDATION_FEATURE_ENABLE_BEST_PRACTICES_EXT);
if (builder.validationFeatures.debugPrint() && supportedValidationFeatures.debugPrintf)
validationFlags.put(VK_VALIDATION_FEATURE_ENABLE_DEBUG_PRINTF_EXT);
if (builder.validationFeatures.synchronization())
validationFlags.put(VK_VALIDATION_FEATURE_ENABLE_SYNCHRONIZATION_VALIDATION_EXT);
validationFlags.flip();
List<String> chosenLayerSettings = new ArrayList<>();

boolean gpuAssisted = builder.validationFeatures.gpuAssisted() && supportedValidationFeatures.gpuAssistedValidation;
boolean debugPrint = builder.validationFeatures.debugPrint() && supportedValidationFeatures.debugPrintf;
if (debugPrint) gpuAssisted = false;

if (gpuAssisted) chosenLayerSettings.add("gpuav_debug_validate_instrumented_shaders");
if (builder.validationFeatures.bestPractices()) chosenLayerSettings.add("validate_best_practices");
if (builder.validationFeatures.synchronization()) chosenLayerSettings.add("validate_sync");
if (builder.vendorBestPractices != null) {
if (builder.vendorBestPractices.arm()) chosenLayerSettings.add("validate_best_practices_arm");
if (builder.vendorBestPractices.amd()) chosenLayerSettings.add("validate_best_practices_amd");
if (builder.vendorBestPractices.img()) chosenLayerSettings.add("validate_best_practices_img");
if (builder.vendorBestPractices.nvidia()) chosenLayerSettings.add("validate_best_practices_nvidia");
}

supportedValidationFeatures.destroy();

if (validationFlags.limit() > 0) pValidationFeatures.pEnabledValidationFeatures(validationFlags);
else pValidationFeatures = null;
int numLayerSettings = chosenLayerSettings.size();
if (gpuAssisted || debugPrint) numLayerSettings += 1;

var pTrue = stack.calloc(4).putInt(0, VK_TRUE);

var vvl = stack.UTF8("VK_LAYER_KHRONOS_validation");
var pValidationSettings = VkLayerSettingEXT.calloc(numLayerSettings, stack);
for (int index = 0; index < chosenLayerSettings.size(); index++) {
var setting = pValidationSettings.get(index);
setting.pLayerName(vvl);
setting.pSettingName(stack.UTF8(chosenLayerSettings.get(index)));
setting.type(VK_LAYER_SETTING_TYPE_BOOL32_EXT);
setting.pValues(pTrue);
VkLayerSettingEXT.nvalueCount(setting.address(), 1);
}

if (gpuAssisted || debugPrint) {
var setting = pValidationSettings.get(chosenLayerSettings.size());
setting.pLayerName(vvl);
setting.pSettingName(stack.UTF8("validate_gpu_based"));
setting.type(VK_LAYER_SETTING_TYPE_INT32_EXT);

int value = debugPrint ? 1 : 2;
setting.pValues(stack.calloc(4).putInt(0, value));
VkLayerSettingEXT.nvalueCount(setting.address(), 1);
}

} else pValidationFeatures = null;
if (numLayerSettings > 0) ciValidationSettings.pSettings(pValidationSettings);
} else ciValidationSettings = null;

var ciInstance = VkInstanceCreateInfo.calloc(stack);
ciInstance.sType$Default();
ciInstance.pNext(pValidationFeatures != null ? pValidationFeatures.address() : 0L);
if (ciValidationSettings != null) ciInstance.pNext(ciValidationSettings);
if (enabledExtensions.contains(VK_KHR_PORTABILITY_ENUMERATION_EXTENSION_NAME)) {
ciInstance.flags(VK_INSTANCE_CREATE_ENUMERATE_PORTABILITY_BIT_KHR);
} else ciInstance.flags(0);
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
package com.github.knokko.boiler.builders.instance;

public record VendorBestPractices(boolean arm, boolean amd, boolean img, boolean nvidia) {
}
Original file line number Diff line number Diff line change
@@ -1,18 +1,23 @@
package com.github.knokko.boiler.builders;

import com.github.knokko.boiler.BoilerInstance;
import com.github.knokko.boiler.builders.instance.ValidationFeatures;
import com.github.knokko.boiler.builders.instance.ValidationFeaturesChecker;
import com.github.knokko.boiler.builders.instance.VendorBestPractices;
import com.github.knokko.boiler.builders.queue.QueueFamilyAllocation;
import com.github.knokko.boiler.builders.queue.QueueFamilyMapping;
import com.github.knokko.boiler.commands.SingleTimeCommands;
import com.github.knokko.boiler.debug.ValidationException;
import com.github.knokko.boiler.exceptions.NoVkPhysicalDeviceException;
import com.github.knokko.boiler.synchronization.ResourceUsage;
import com.github.knokko.boiler.utilities.CollectionHelper;
import org.junit.jupiter.api.Test;
import org.lwjgl.vulkan.*;

import java.util.HashSet;
import java.util.Objects;

import static com.github.knokko.boiler.exceptions.VulkanFailureException.assertVkSuccess;
import static com.github.knokko.boiler.utilities.CollectionHelper.createSet;
import static org.junit.jupiter.api.Assertions.*;
import static org.lwjgl.system.MemoryStack.stackPush;
Expand Down Expand Up @@ -385,4 +390,52 @@ public void testApiDump() {
assertEquals("Mission completed", message);
}
}

private void triggerNvidiaBestPracticeWarning(BoilerBuilder builder) {
var instance = builder.build();

// var image = boiler.images.createSimple(
// 10, 10, VK_FORMAT_R8_SINT, VK_IMAGE_USAGE_SAMPLED_BIT,
// VK_IMAGE_ASPECT_COLOR_BIT, "DummyImage"
// );
//
// var commands = new SingleTimeCommands(boiler);
// commands.submit("CauseWarning", recorder -> {
// recorder.transitionLayout(image, null, ResourceUsage.shaderRead(VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT));
// }).awaitCompletion();
// commands.destroy();
//
// image.destroy(boiler);

try (var stack = stackPush()) {
var allocateInfo = VkMemoryAllocateInfo.calloc(stack);
allocateInfo.sType$Default();
allocateInfo.allocationSize(123);
allocateInfo.memoryTypeIndex(0);

var pMemory = stack.callocLong(1);
for (int counter = 0; counter < 1; counter++) {
assertVkSuccess(vkAllocateMemory(
instance.vkDevice(), allocateInfo, null, pMemory
), "AllocateMemory", "trigger-nvidia-warnings");

vkFreeMemory(instance.vkDevice(), pMemory.get(0), null);
}
}
instance.destroyInitialObjects();
}

@Test
public void testBestPracticesDefault() {
triggerNvidiaBestPracticeWarning(new BoilerBuilder(
VK_API_VERSION_1_0, "TestBestPracticeDefault", 1
).bestPractices().validation());
}

@Test
public void testBestPracticesNvidia() {
triggerNvidiaBestPracticeWarning(new BoilerBuilder(
VK_API_VERSION_1_2, "TestBestPracticesNvidia", 1
).validation(new ValidationFeatures(false, false, false, true, false)));
}
}

0 comments on commit fdaa6f2

Please sign in to comment.