mirror of
https://github.com/Droid-Deck/DroidDeck.git
synced 2026-10-16 04:07:17 -04:00
Mali compatibility layer: multiDrawIndirect, depthClipEnable and robustness2 for DXVK on Venus
A Galaxy A15 (Mali-G57) on Venus got gamescope and Steam up, but DXVK refused the GPU: "Device does not support required feature 'multiDrawIndirect'". DXVK 3.1 stops at the first missing feature, so the rest of its required list (dxvk_device_info.cpp) was checked against what the testers' Mali drivers cannot have, and covered in the same pass, on top of David Cimo's six: - multiDrawIndirect: reported, taken off the device, and an indirect draw with drawCount > 1 is recorded as single draws at offset + i * stride; maxDrawIndirectCount reported as 2^30. (drawIndirectCount is optional for DXVK and stays as the driver says.) - VK_EXT_depth_clip_enable (required): offered when the driver lacks it; depthClipEnable off in a pipeline becomes depthClampEnable, and the extension's structures never reach the driver. - VK_EXT_robustness2 missing entirely (gamescope saw the same on these phones): offered with robustBufferAccess2 (as robustBufferAccess, as before) and nullDescriptor, emulated by small stand-ins (a zeroed buffer, a 1x1 image) for VK_NULL_HANDLE buffers, image views and vertex buffers in plain, template and push descriptor writes and vertex-buffer binds. A null texel-buffer view stays null (its format is not known). The layer logs every feature it emulates per device.
This commit is contained in:
1 parent
6c7242aa64
commit
22694a380d
4 files changed
+631
-6
No files matched your search
@@ -0,0 +1,411 @@
|
||||
/*
|
||||
* The Mali compatibility layer's draw and descriptor emulation (added to David Cimo's layer):
|
||||
*
|
||||
* - multiDrawIndirect: an indirect draw with drawCount > 1 is recorded as drawCount single draws
|
||||
* at offset + i * stride. Mali-G57 (Bifrost/Valhall v9) has none, and DXVK refuses the device.
|
||||
* - robustness2's nullDescriptor: VK_NULL_HANDLE buffers, image views and vertex buffers in
|
||||
* descriptor writes (plain, template and push) and vertex-buffer binds are replaced with small
|
||||
* stand-ins the layer owns. robustBufferAccess2 itself maps to robustBufferAccess (layer.c).
|
||||
* A texel-buffer view stays null: its format is not known here.
|
||||
*/
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "mali_compat.h"
|
||||
|
||||
/* --- multiDrawIndirect --- */
|
||||
|
||||
VKAPI_ATTR void VKAPI_CALL CmdDrawIndirect(VkCommandBuffer cmd, VkBuffer buffer, VkDeviceSize offset,
|
||||
uint32_t draw_count, uint32_t stride)
|
||||
{
|
||||
struct device *dev = device_from_handle(cmd);
|
||||
if (draw_count <= 1) {
|
||||
dev->CmdDrawIndirect(cmd, buffer, offset, draw_count, stride);
|
||||
return;
|
||||
}
|
||||
for (uint32_t i = 0; i < draw_count; i++)
|
||||
dev->CmdDrawIndirect(cmd, buffer, offset + (VkDeviceSize)i * stride, 1, stride);
|
||||
}
|
||||
|
||||
VKAPI_ATTR void VKAPI_CALL CmdDrawIndexedIndirect(VkCommandBuffer cmd, VkBuffer buffer, VkDeviceSize offset,
|
||||
uint32_t draw_count, uint32_t stride)
|
||||
{
|
||||
struct device *dev = device_from_handle(cmd);
|
||||
if (draw_count <= 1) {
|
||||
dev->CmdDrawIndexedIndirect(cmd, buffer, offset, draw_count, stride);
|
||||
return;
|
||||
}
|
||||
for (uint32_t i = 0; i < draw_count; i++)
|
||||
dev->CmdDrawIndexedIndirect(cmd, buffer, offset + (VkDeviceSize)i * stride, 1, stride);
|
||||
}
|
||||
|
||||
/* --- nullDescriptor stand-ins --- */
|
||||
|
||||
/* A template's entries, to find the null handles in the data it is given. */
|
||||
struct template_info {
|
||||
uint32_t count;
|
||||
VkDescriptorUpdateTemplateEntry *entries;
|
||||
size_t size; /* bytes the data spans */
|
||||
};
|
||||
|
||||
#define NULL_BUFFER_SIZE 65536
|
||||
|
||||
static uint32_t memory_type(const struct device *dev, uint32_t bits, VkMemoryPropertyFlags want)
|
||||
{
|
||||
for (uint32_t i = 0; i < dev->memory_properties.memoryTypeCount; i++)
|
||||
if ((bits & (1u << i)) && (dev->memory_properties.memoryTypes[i].propertyFlags & want) == want)
|
||||
return i;
|
||||
for (uint32_t i = 0; i < dev->memory_properties.memoryTypeCount; i++)
|
||||
if (bits & (1u << i))
|
||||
return i;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Made once per device, under its lock, the first time a null descriptor is seen. */
|
||||
static bool null_resources(struct device *dev)
|
||||
{
|
||||
if (dev->null_ready)
|
||||
return dev->null_ready > 0;
|
||||
dev->null_ready = -1;
|
||||
|
||||
VkBufferCreateInfo binfo = {
|
||||
.sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO,
|
||||
.size = NULL_BUFFER_SIZE,
|
||||
.usage = VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT | VK_BUFFER_USAGE_STORAGE_BUFFER_BIT |
|
||||
VK_BUFFER_USAGE_VERTEX_BUFFER_BIT | VK_BUFFER_USAGE_INDEX_BUFFER_BIT,
|
||||
.sharingMode = VK_SHARING_MODE_EXCLUSIVE,
|
||||
};
|
||||
if (dev->CreateBuffer(dev->handle, &binfo, NULL, &dev->null_buffer) != VK_SUCCESS)
|
||||
return false;
|
||||
VkMemoryRequirements breq;
|
||||
dev->GetBufferMemoryRequirements(dev->handle, dev->null_buffer, &breq);
|
||||
VkMemoryAllocateInfo balloc = {
|
||||
.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO,
|
||||
.allocationSize = breq.size,
|
||||
.memoryTypeIndex = memory_type(dev, breq.memoryTypeBits,
|
||||
VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT),
|
||||
};
|
||||
if (dev->AllocateMemory(dev->handle, &balloc, NULL, &dev->null_buffer_memory) != VK_SUCCESS)
|
||||
return false;
|
||||
dev->BindBufferMemory(dev->handle, dev->null_buffer, dev->null_buffer_memory, 0);
|
||||
/* A null buffer reads as zeros. */
|
||||
void *data = NULL;
|
||||
if ((dev->memory_properties.memoryTypes[balloc.memoryTypeIndex].propertyFlags & VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT) &&
|
||||
dev->MapMemory(dev->handle, dev->null_buffer_memory, 0, VK_WHOLE_SIZE, 0, &data) == VK_SUCCESS) {
|
||||
memset(data, 0, (size_t)breq.size);
|
||||
dev->UnmapMemory(dev->handle, dev->null_buffer_memory);
|
||||
}
|
||||
|
||||
VkImageCreateInfo iinfo = {
|
||||
.sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO,
|
||||
.imageType = VK_IMAGE_TYPE_2D,
|
||||
.format = VK_FORMAT_R8G8B8A8_UNORM,
|
||||
.extent = {1, 1, 1},
|
||||
.mipLevels = 1,
|
||||
.arrayLayers = 1,
|
||||
.samples = VK_SAMPLE_COUNT_1_BIT,
|
||||
.tiling = VK_IMAGE_TILING_OPTIMAL,
|
||||
.usage = VK_IMAGE_USAGE_SAMPLED_BIT | VK_IMAGE_USAGE_STORAGE_BIT,
|
||||
.sharingMode = VK_SHARING_MODE_EXCLUSIVE,
|
||||
.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED,
|
||||
};
|
||||
if (dev->CreateImage(dev->handle, &iinfo, NULL, &dev->null_image) != VK_SUCCESS)
|
||||
return false;
|
||||
VkMemoryRequirements ireq;
|
||||
dev->GetImageMemoryRequirements(dev->handle, dev->null_image, &ireq);
|
||||
VkMemoryAllocateInfo ialloc = {
|
||||
.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO,
|
||||
.allocationSize = ireq.size,
|
||||
.memoryTypeIndex = memory_type(dev, ireq.memoryTypeBits, VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT),
|
||||
};
|
||||
if (dev->AllocateMemory(dev->handle, &ialloc, NULL, &dev->null_image_memory) != VK_SUCCESS)
|
||||
return false;
|
||||
dev->BindImageMemory(dev->handle, dev->null_image, dev->null_image_memory, 0);
|
||||
VkImageViewCreateInfo vinfo = {
|
||||
.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO,
|
||||
.image = dev->null_image,
|
||||
.viewType = VK_IMAGE_VIEW_TYPE_2D,
|
||||
.format = VK_FORMAT_R8G8B8A8_UNORM,
|
||||
.subresourceRange = {VK_IMAGE_ASPECT_COLOR_BIT, 0, 1, 0, 1},
|
||||
};
|
||||
if (dev->CreateImageView(dev->handle, &vinfo, NULL, &dev->null_view) != VK_SUCCESS)
|
||||
return false;
|
||||
dev->null_ready = 1;
|
||||
layer_log("nullDescriptor: stand-in buffer and 1x1 image ready");
|
||||
return true;
|
||||
}
|
||||
|
||||
void null_resources_destroy(struct device *dev)
|
||||
{
|
||||
for (uint32_t i = 0; i < dev->templates.capacity; i++) {
|
||||
struct template_info *t = dev->templates.values ? dev->templates.values[i] : NULL;
|
||||
if (t) {
|
||||
free(t->entries);
|
||||
free(t);
|
||||
}
|
||||
}
|
||||
map_free(&dev->templates);
|
||||
if (dev->null_view) dev->DestroyImageView(dev->handle, dev->null_view, NULL);
|
||||
if (dev->null_image) dev->DestroyImage(dev->handle, dev->null_image, NULL);
|
||||
if (dev->null_image_memory) dev->FreeMemory(dev->handle, dev->null_image_memory, NULL);
|
||||
if (dev->null_buffer) dev->DestroyBuffer(dev->handle, dev->null_buffer, NULL);
|
||||
if (dev->null_buffer_memory) dev->FreeMemory(dev->handle, dev->null_buffer_memory, NULL);
|
||||
}
|
||||
|
||||
static bool is_buffer_type(VkDescriptorType t)
|
||||
{
|
||||
return t == VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER || t == VK_DESCRIPTOR_TYPE_STORAGE_BUFFER ||
|
||||
t == VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC || t == VK_DESCRIPTOR_TYPE_STORAGE_BUFFER_DYNAMIC;
|
||||
}
|
||||
|
||||
static bool is_image_type(VkDescriptorType t)
|
||||
{
|
||||
return t == VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE || t == VK_DESCRIPTOR_TYPE_STORAGE_IMAGE ||
|
||||
t == VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER || t == VK_DESCRIPTOR_TYPE_INPUT_ATTACHMENT;
|
||||
}
|
||||
|
||||
static void fix_buffer(struct device *dev, VkDescriptorBufferInfo *info)
|
||||
{
|
||||
if (info->buffer != VK_NULL_HANDLE || !null_resources(dev))
|
||||
return;
|
||||
info->buffer = dev->null_buffer;
|
||||
info->offset = 0;
|
||||
info->range = VK_WHOLE_SIZE;
|
||||
}
|
||||
|
||||
static void fix_image(struct device *dev, VkDescriptorImageInfo *info)
|
||||
{
|
||||
if (info->imageView != VK_NULL_HANDLE || !null_resources(dev))
|
||||
return;
|
||||
info->imageView = dev->null_view;
|
||||
}
|
||||
|
||||
/* Copies of the writes with stand-ins for null handles; NULL when nothing needed changing. */
|
||||
static VkWriteDescriptorSet *fix_writes(struct device *dev, uint32_t count, const VkWriteDescriptorSet *writes,
|
||||
void ***scratch, uint32_t *scratch_count)
|
||||
{
|
||||
VkWriteDescriptorSet *copies = NULL;
|
||||
for (uint32_t i = 0; i < count; i++) {
|
||||
const VkWriteDescriptorSet *w = &writes[i];
|
||||
bool null_found = false;
|
||||
for (uint32_t j = 0; j < w->descriptorCount && !null_found; j++) {
|
||||
if (is_buffer_type(w->descriptorType) && w->pBufferInfo && w->pBufferInfo[j].buffer == VK_NULL_HANDLE)
|
||||
null_found = true;
|
||||
if (is_image_type(w->descriptorType) && w->pImageInfo && w->pImageInfo[j].imageView == VK_NULL_HANDLE &&
|
||||
w->descriptorType != VK_DESCRIPTOR_TYPE_SAMPLER)
|
||||
null_found = true;
|
||||
}
|
||||
if (!null_found)
|
||||
continue;
|
||||
if (!copies) {
|
||||
copies = malloc(count * sizeof(*copies));
|
||||
memcpy(copies, writes, count * sizeof(*copies));
|
||||
*scratch = calloc(count, sizeof(void *));
|
||||
}
|
||||
if (is_buffer_type(w->descriptorType)) {
|
||||
VkDescriptorBufferInfo *b = malloc(w->descriptorCount * sizeof(*b));
|
||||
memcpy(b, w->pBufferInfo, w->descriptorCount * sizeof(*b));
|
||||
for (uint32_t j = 0; j < w->descriptorCount; j++)
|
||||
fix_buffer(dev, &b[j]);
|
||||
copies[i].pBufferInfo = b;
|
||||
(*scratch)[(*scratch_count)++] = b;
|
||||
} else {
|
||||
VkDescriptorImageInfo *im = malloc(w->descriptorCount * sizeof(*im));
|
||||
memcpy(im, w->pImageInfo, w->descriptorCount * sizeof(*im));
|
||||
for (uint32_t j = 0; j < w->descriptorCount; j++)
|
||||
fix_image(dev, &im[j]);
|
||||
copies[i].pImageInfo = im;
|
||||
(*scratch)[(*scratch_count)++] = im;
|
||||
}
|
||||
}
|
||||
return copies;
|
||||
}
|
||||
|
||||
static void free_scratch(void **scratch, uint32_t count)
|
||||
{
|
||||
for (uint32_t i = 0; i < count; i++)
|
||||
free(scratch[i]);
|
||||
free(scratch);
|
||||
}
|
||||
|
||||
VKAPI_ATTR void VKAPI_CALL UpdateDescriptorSets(VkDevice device, uint32_t write_count, const VkWriteDescriptorSet *writes,
|
||||
uint32_t copy_count, const VkCopyDescriptorSet *copies)
|
||||
{
|
||||
struct device *dev = device_from_handle(device);
|
||||
pthread_mutex_lock(&dev->lock);
|
||||
void **scratch = NULL;
|
||||
uint32_t scratch_count = 0;
|
||||
VkWriteDescriptorSet *fixed = fix_writes(dev, write_count, writes, &scratch, &scratch_count);
|
||||
pthread_mutex_unlock(&dev->lock);
|
||||
dev->UpdateDescriptorSets(device, write_count, fixed ? fixed : writes, copy_count, copies);
|
||||
free(fixed);
|
||||
free_scratch(scratch, scratch_count);
|
||||
}
|
||||
|
||||
VKAPI_ATTR void VKAPI_CALL CmdPushDescriptorSet(VkCommandBuffer cmd, VkPipelineBindPoint bind_point,
|
||||
VkPipelineLayout layout, uint32_t set, uint32_t write_count,
|
||||
const VkWriteDescriptorSet *writes)
|
||||
{
|
||||
struct device *dev = device_from_handle(cmd);
|
||||
pthread_mutex_lock(&dev->lock);
|
||||
void **scratch = NULL;
|
||||
uint32_t scratch_count = 0;
|
||||
VkWriteDescriptorSet *fixed = fix_writes(dev, write_count, writes, &scratch, &scratch_count);
|
||||
pthread_mutex_unlock(&dev->lock);
|
||||
dev->CmdPushDescriptorSet(cmd, bind_point, layout, set, write_count, fixed ? fixed : writes);
|
||||
free(fixed);
|
||||
free_scratch(scratch, scratch_count);
|
||||
}
|
||||
|
||||
static size_t entry_size(VkDescriptorType t)
|
||||
{
|
||||
if (is_buffer_type(t))
|
||||
return sizeof(VkDescriptorBufferInfo);
|
||||
if (is_image_type(t) || t == VK_DESCRIPTOR_TYPE_SAMPLER)
|
||||
return sizeof(VkDescriptorImageInfo);
|
||||
if (t == VK_DESCRIPTOR_TYPE_INLINE_UNIFORM_BLOCK)
|
||||
return 1;
|
||||
return sizeof(uint64_t);
|
||||
}
|
||||
|
||||
VKAPI_ATTR VkResult VKAPI_CALL CreateDescriptorUpdateTemplate(VkDevice device,
|
||||
const VkDescriptorUpdateTemplateCreateInfo *info,
|
||||
const VkAllocationCallbacks *allocator,
|
||||
VkDescriptorUpdateTemplate *tmpl)
|
||||
{
|
||||
struct device *dev = device_from_handle(device);
|
||||
VkResult result = dev->CreateDescriptorUpdateTemplate(device, info, allocator, tmpl);
|
||||
if (result != VK_SUCCESS)
|
||||
return result;
|
||||
struct template_info *t = calloc(1, sizeof(*t));
|
||||
t->count = info->descriptorUpdateEntryCount;
|
||||
t->entries = malloc(t->count * sizeof(*t->entries));
|
||||
memcpy(t->entries, info->pDescriptorUpdateEntries, t->count * sizeof(*t->entries));
|
||||
for (uint32_t i = 0; i < t->count; i++) {
|
||||
const VkDescriptorUpdateTemplateEntry *e = &t->entries[i];
|
||||
size_t end = e->descriptorType == VK_DESCRIPTOR_TYPE_INLINE_UNIFORM_BLOCK
|
||||
? e->offset + e->descriptorCount
|
||||
: e->offset + (e->descriptorCount ? (e->descriptorCount - 1) * e->stride : 0) + entry_size(e->descriptorType);
|
||||
if (end > t->size)
|
||||
t->size = end;
|
||||
}
|
||||
pthread_mutex_lock(&dev->lock);
|
||||
map_put(&dev->templates, (uint64_t)*tmpl, t);
|
||||
pthread_mutex_unlock(&dev->lock);
|
||||
return VK_SUCCESS;
|
||||
}
|
||||
|
||||
VKAPI_ATTR void VKAPI_CALL DestroyDescriptorUpdateTemplate(VkDevice device, VkDescriptorUpdateTemplate tmpl,
|
||||
const VkAllocationCallbacks *allocator)
|
||||
{
|
||||
struct device *dev = device_from_handle(device);
|
||||
pthread_mutex_lock(&dev->lock);
|
||||
struct template_info *t = map_remove(&dev->templates, (uint64_t)tmpl);
|
||||
pthread_mutex_unlock(&dev->lock);
|
||||
if (t) {
|
||||
free(t->entries);
|
||||
free(t);
|
||||
}
|
||||
dev->DestroyDescriptorUpdateTemplate(device, tmpl, allocator);
|
||||
}
|
||||
|
||||
/* A copy of the template's data with stand-ins for null handles; NULL when nothing changed. */
|
||||
static void *fix_template_data(struct device *dev, VkDescriptorUpdateTemplate tmpl, const void *data)
|
||||
{
|
||||
pthread_mutex_lock(&dev->lock);
|
||||
struct template_info *t = map_get(&dev->templates, (uint64_t)tmpl);
|
||||
void *copy = NULL;
|
||||
if (t && data) {
|
||||
for (uint32_t i = 0; i < t->count; i++) {
|
||||
const VkDescriptorUpdateTemplateEntry *e = &t->entries[i];
|
||||
bool buffer = is_buffer_type(e->descriptorType);
|
||||
bool image = is_image_type(e->descriptorType);
|
||||
if (!buffer && !image)
|
||||
continue;
|
||||
for (uint32_t j = 0; j < e->descriptorCount; j++) {
|
||||
size_t at = e->offset + (size_t)j * e->stride;
|
||||
const char *src = (const char *)(copy ? copy : data) + at;
|
||||
bool null_handle = buffer ? ((const VkDescriptorBufferInfo *)src)->buffer == VK_NULL_HANDLE
|
||||
: ((const VkDescriptorImageInfo *)src)->imageView == VK_NULL_HANDLE;
|
||||
if (!null_handle)
|
||||
continue;
|
||||
if (!copy) {
|
||||
copy = malloc(t->size);
|
||||
memcpy(copy, data, t->size);
|
||||
}
|
||||
if (buffer)
|
||||
fix_buffer(dev, (VkDescriptorBufferInfo *)((char *)copy + at));
|
||||
else
|
||||
fix_image(dev, (VkDescriptorImageInfo *)((char *)copy + at));
|
||||
}
|
||||
}
|
||||
}
|
||||
pthread_mutex_unlock(&dev->lock);
|
||||
return copy;
|
||||
}
|
||||
|
||||
VKAPI_ATTR void VKAPI_CALL UpdateDescriptorSetWithTemplate(VkDevice device, VkDescriptorSet set,
|
||||
VkDescriptorUpdateTemplate tmpl, const void *data)
|
||||
{
|
||||
struct device *dev = device_from_handle(device);
|
||||
void *fixed = fix_template_data(dev, tmpl, data);
|
||||
dev->UpdateDescriptorSetWithTemplate(device, set, tmpl, fixed ? fixed : data);
|
||||
free(fixed);
|
||||
}
|
||||
|
||||
VKAPI_ATTR void VKAPI_CALL CmdPushDescriptorSetWithTemplate(VkCommandBuffer cmd, VkDescriptorUpdateTemplate tmpl,
|
||||
VkPipelineLayout layout, uint32_t set, const void *data)
|
||||
{
|
||||
struct device *dev = device_from_handle(cmd);
|
||||
void *fixed = fix_template_data(dev, tmpl, data);
|
||||
dev->CmdPushDescriptorSetWithTemplate(cmd, tmpl, layout, set, fixed ? fixed : data);
|
||||
free(fixed);
|
||||
}
|
||||
|
||||
/* Null vertex buffers read as zeros: bound to the stand-in at offset 0. */
|
||||
VKAPI_ATTR void VKAPI_CALL CmdBindVertexBuffers(VkCommandBuffer cmd, uint32_t first, uint32_t count,
|
||||
const VkBuffer *buffers, const VkDeviceSize *offsets)
|
||||
{
|
||||
struct device *dev = device_from_handle(cmd);
|
||||
VkBuffer fixed[64];
|
||||
VkDeviceSize fixed_offsets[64];
|
||||
bool any = false;
|
||||
for (uint32_t i = 0; i < count && i < 64; i++) any |= buffers[i] == VK_NULL_HANDLE;
|
||||
if (!any || count > 64) {
|
||||
dev->CmdBindVertexBuffers(cmd, first, count, buffers, offsets);
|
||||
return;
|
||||
}
|
||||
pthread_mutex_lock(&dev->lock);
|
||||
bool ready = null_resources(dev);
|
||||
pthread_mutex_unlock(&dev->lock);
|
||||
for (uint32_t i = 0; i < count; i++) {
|
||||
fixed[i] = buffers[i] == VK_NULL_HANDLE && ready ? dev->null_buffer : buffers[i];
|
||||
fixed_offsets[i] = buffers[i] == VK_NULL_HANDLE ? 0 : offsets[i];
|
||||
}
|
||||
dev->CmdBindVertexBuffers(cmd, first, count, fixed, fixed_offsets);
|
||||
}
|
||||
|
||||
VKAPI_ATTR void VKAPI_CALL CmdBindVertexBuffers2(VkCommandBuffer cmd, uint32_t first, uint32_t count,
|
||||
const VkBuffer *buffers, const VkDeviceSize *offsets,
|
||||
const VkDeviceSize *sizes, const VkDeviceSize *strides)
|
||||
{
|
||||
struct device *dev = device_from_handle(cmd);
|
||||
VkBuffer fixed[64];
|
||||
VkDeviceSize fixed_offsets[64], fixed_sizes[64];
|
||||
bool any = false;
|
||||
for (uint32_t i = 0; i < count && i < 64; i++) any |= buffers[i] == VK_NULL_HANDLE;
|
||||
if (!any || count > 64) {
|
||||
dev->CmdBindVertexBuffers2(cmd, first, count, buffers, offsets, sizes, strides);
|
||||
return;
|
||||
}
|
||||
pthread_mutex_lock(&dev->lock);
|
||||
bool ready = null_resources(dev);
|
||||
pthread_mutex_unlock(&dev->lock);
|
||||
for (uint32_t i = 0; i < count; i++) {
|
||||
bool null_buffer = buffers[i] == VK_NULL_HANDLE;
|
||||
fixed[i] = null_buffer && ready ? dev->null_buffer : buffers[i];
|
||||
fixed_offsets[i] = null_buffer ? 0 : offsets[i];
|
||||
fixed_sizes[i] = sizes ? (null_buffer ? NULL_BUFFER_SIZE : sizes[i]) : 0;
|
||||
}
|
||||
dev->CmdBindVertexBuffers2(cmd, first, count, fixed, fixed_offsets, sizes ? fixed_sizes : NULL, strides);
|
||||
}
|
||||
+153
-4
@@ -190,6 +190,14 @@ uint32_t physical_device_gaps(struct instance *inst, VkPhysicalDevice physical_d
|
||||
gaps |= GAP_BC;
|
||||
if (robustness2 && !robust.robustBufferAccess2)
|
||||
gaps |= GAP_ROBUSTNESS2;
|
||||
if (!features.features.multiDrawIndirect)
|
||||
gaps |= GAP_MULTI_DRAW;
|
||||
if (!has_extension(inst, physical_device, VK_EXT_DEPTH_CLIP_ENABLE_EXTENSION_NAME))
|
||||
gaps |= GAP_DEPTH_CLIP;
|
||||
/* No robustness2 at all: the extension is offered with robustBufferAccess2 (as robustBufferAccess)
|
||||
* and nullDescriptor (stand-ins, draw.c). */
|
||||
if (!robustness2)
|
||||
gaps |= GAP_ROBUSTNESS2 | GAP_NULL_DESCRIPTOR;
|
||||
|
||||
pthread_mutex_lock(&inst->lock);
|
||||
if (inst->physical_device_count < sizeof(inst->physical_devices) / sizeof(inst->physical_devices[0])) {
|
||||
@@ -200,6 +208,48 @@ uint32_t physical_device_gaps(struct instance *inst, VkPhysicalDevice physical_d
|
||||
return gaps;
|
||||
}
|
||||
|
||||
/* Structures of extensions the driver does not have are taken out of a chain for the call down and
|
||||
* put back after it: the driver (and Venus) must not see them. */
|
||||
struct unlinked {
|
||||
VkBaseOutStructure *prev, *node;
|
||||
};
|
||||
|
||||
static uint32_t unlink_types(void *head, const VkStructureType *types, uint32_t type_count,
|
||||
struct unlinked *out, uint32_t max)
|
||||
{
|
||||
uint32_t n = 0;
|
||||
VkBaseOutStructure *prev = head;
|
||||
while (prev && prev->pNext && n < max) {
|
||||
VkBaseOutStructure *s = prev->pNext;
|
||||
bool drop = false;
|
||||
for (uint32_t i = 0; i < type_count; i++)
|
||||
drop |= s->sType == types[i];
|
||||
if (drop) {
|
||||
out[n++] = (struct unlinked){prev, s};
|
||||
prev->pNext = s->pNext;
|
||||
} else {
|
||||
prev = s;
|
||||
}
|
||||
}
|
||||
return n;
|
||||
}
|
||||
|
||||
static void relink(struct unlinked *list, uint32_t n)
|
||||
{
|
||||
while (n--)
|
||||
list[n].prev->pNext = list[n].node;
|
||||
}
|
||||
|
||||
static uint32_t foreign_types(uint32_t gaps, VkStructureType *types)
|
||||
{
|
||||
uint32_t n = 0;
|
||||
if (gaps & GAP_DEPTH_CLIP)
|
||||
types[n++] = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DEPTH_CLIP_ENABLE_FEATURES_EXT;
|
||||
if (gaps & GAP_NULL_DESCRIPTOR)
|
||||
types[n++] = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_ROBUSTNESS_2_FEATURES_EXT;
|
||||
return n;
|
||||
}
|
||||
|
||||
static void report_features(VkPhysicalDeviceFeatures *features, uint32_t gaps)
|
||||
{
|
||||
if (gaps & GAP_FILL_MODE)
|
||||
@@ -212,6 +262,8 @@ static void report_features(VkPhysicalDeviceFeatures *features, uint32_t gaps)
|
||||
features->shaderCullDistance = VK_TRUE;
|
||||
if (gaps & GAP_BC)
|
||||
features->textureCompressionBC = VK_TRUE;
|
||||
if (gaps & GAP_MULTI_DRAW)
|
||||
features->multiDrawIndirect = VK_TRUE;
|
||||
}
|
||||
|
||||
/* Which made-up features the application asked for, and off with them before the driver sees them. */
|
||||
@@ -238,6 +290,10 @@ static uint32_t take_features(VkPhysicalDeviceFeatures *features, uint32_t gaps)
|
||||
requested |= GAP_BC;
|
||||
features->textureCompressionBC = VK_FALSE;
|
||||
}
|
||||
if ((gaps & GAP_MULTI_DRAW) && features->multiDrawIndirect) {
|
||||
requested |= GAP_MULTI_DRAW;
|
||||
features->multiDrawIndirect = VK_FALSE;
|
||||
}
|
||||
return requested;
|
||||
}
|
||||
|
||||
@@ -245,6 +301,8 @@ static void report_limits(VkPhysicalDeviceLimits *limits, uint32_t gaps)
|
||||
{
|
||||
if (gaps & GAP_MULTI_VIEWPORT)
|
||||
limits->maxViewports = 16;
|
||||
if ((gaps & GAP_MULTI_DRAW) && limits->maxDrawIndirectCount < (1u << 30))
|
||||
limits->maxDrawIndirectCount = 1u << 30;
|
||||
if (gaps & GAPS_SHADER) {
|
||||
limits->maxClipDistances = 8;
|
||||
limits->maxCullDistances = 8;
|
||||
@@ -264,12 +322,21 @@ static VKAPI_ATTR void VKAPI_CALL GetPhysicalDeviceFeatures2(VkPhysicalDevice ph
|
||||
VkPhysicalDeviceFeatures2 *features)
|
||||
{
|
||||
struct instance *inst = instance_from_handle(physical_device);
|
||||
inst->GetPhysicalDeviceFeatures2(physical_device, features);
|
||||
uint32_t gaps = physical_device_gaps(inst, physical_device);
|
||||
VkStructureType types[4];
|
||||
struct unlinked dropped[8];
|
||||
uint32_t dropped_count = unlink_types(features, types, foreign_types(gaps, types), dropped, 8);
|
||||
inst->GetPhysicalDeviceFeatures2(physical_device, features);
|
||||
relink(dropped, dropped_count);
|
||||
report_features(&features->features, gaps);
|
||||
for (VkBaseOutStructure *s = features->pNext; s; s = s->pNext) {
|
||||
if (s->sType == VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_ROBUSTNESS_2_FEATURES_EXT && (gaps & GAP_ROBUSTNESS2))
|
||||
if (s->sType == VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_ROBUSTNESS_2_FEATURES_EXT && (gaps & GAP_ROBUSTNESS2)) {
|
||||
((VkPhysicalDeviceRobustness2FeaturesEXT *)s)->robustBufferAccess2 = VK_TRUE;
|
||||
if (gaps & GAP_NULL_DESCRIPTOR)
|
||||
((VkPhysicalDeviceRobustness2FeaturesEXT *)s)->nullDescriptor = VK_TRUE;
|
||||
}
|
||||
if (s->sType == VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DEPTH_CLIP_ENABLE_FEATURES_EXT && (gaps & GAP_DEPTH_CLIP))
|
||||
((VkPhysicalDeviceDepthClipEnableFeaturesEXT *)s)->depthClipEnable = VK_TRUE;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -289,6 +356,40 @@ static VKAPI_ATTR void VKAPI_CALL GetPhysicalDeviceProperties2(VkPhysicalDevice
|
||||
report_limits(&properties->properties.limits, physical_device_gaps(inst, physical_device));
|
||||
}
|
||||
|
||||
/* The extensions the layer stands in for, added to the driver's list. */
|
||||
static VKAPI_ATTR VkResult VKAPI_CALL EnumerateDeviceExtensionProperties(VkPhysicalDevice physical_device,
|
||||
const char *layer_name, uint32_t *count,
|
||||
VkExtensionProperties *properties)
|
||||
{
|
||||
struct instance *inst = instance_from_handle(physical_device);
|
||||
if (layer_name)
|
||||
return inst->EnumerateDeviceExtensionProperties(physical_device, layer_name, count, properties);
|
||||
uint32_t gaps = physical_device_gaps(inst, physical_device);
|
||||
VkExtensionProperties extra[2];
|
||||
uint32_t extra_count = 0;
|
||||
if (gaps & GAP_DEPTH_CLIP)
|
||||
extra[extra_count++] = (VkExtensionProperties){VK_EXT_DEPTH_CLIP_ENABLE_EXTENSION_NAME, 1};
|
||||
if (gaps & GAP_NULL_DESCRIPTOR)
|
||||
extra[extra_count++] = (VkExtensionProperties){VK_EXT_ROBUSTNESS_2_EXTENSION_NAME, 1};
|
||||
uint32_t own = 0;
|
||||
VkResult result = inst->EnumerateDeviceExtensionProperties(physical_device, NULL, &own, NULL);
|
||||
if (result != VK_SUCCESS)
|
||||
return result;
|
||||
if (!properties) {
|
||||
*count = own + extra_count;
|
||||
return VK_SUCCESS;
|
||||
}
|
||||
VkExtensionProperties *all = calloc(own + extra_count, sizeof(*all));
|
||||
inst->EnumerateDeviceExtensionProperties(physical_device, NULL, &own, all);
|
||||
memcpy(all + own, extra, extra_count * sizeof(*extra));
|
||||
uint32_t total = own + extra_count;
|
||||
uint32_t n = *count < total ? *count : total;
|
||||
memcpy(properties, all, n * sizeof(*all));
|
||||
free(all);
|
||||
*count = n;
|
||||
return n < total ? VK_INCOMPLETE : VK_SUCCESS;
|
||||
}
|
||||
|
||||
static VKAPI_ATTR VkResult VKAPI_CALL CreateInstance(const VkInstanceCreateInfo *info,
|
||||
const VkAllocationCallbacks *allocator, VkInstance *instance)
|
||||
{
|
||||
@@ -410,8 +511,35 @@ static VKAPI_ATTR VkResult VKAPI_CALL CreateDevice(VkPhysicalDevice physical_dev
|
||||
enabled->robustBufferAccess = VK_TRUE;
|
||||
}
|
||||
|
||||
/* The extensions the layer stands in for leave the list, and their structures the chain. */
|
||||
const char **names = NULL;
|
||||
if (gaps & (GAP_DEPTH_CLIP | GAP_NULL_DESCRIPTOR)) {
|
||||
names = malloc((info->enabledExtensionCount ? info->enabledExtensionCount : 1) * sizeof(*names));
|
||||
copy.enabledExtensionCount = 0;
|
||||
for (uint32_t i = 0; i < info->enabledExtensionCount; i++) {
|
||||
const char *name = info->ppEnabledExtensionNames[i];
|
||||
if ((gaps & GAP_DEPTH_CLIP) && !strcmp(name, VK_EXT_DEPTH_CLIP_ENABLE_EXTENSION_NAME)) {
|
||||
requested |= GAP_DEPTH_CLIP;
|
||||
continue;
|
||||
}
|
||||
if ((gaps & GAP_NULL_DESCRIPTOR) && !strcmp(name, VK_EXT_ROBUSTNESS_2_EXTENSION_NAME)) {
|
||||
requested |= GAP_NULL_DESCRIPTOR;
|
||||
if (enabled)
|
||||
enabled->robustBufferAccess = VK_TRUE;
|
||||
continue;
|
||||
}
|
||||
names[copy.enabledExtensionCount++] = name;
|
||||
}
|
||||
copy.ppEnabledExtensionNames = names;
|
||||
}
|
||||
VkStructureType foreign[4];
|
||||
struct unlinked dropped[8];
|
||||
uint32_t dropped_count = unlink_types(©, foreign, foreign_types(gaps, foreign), dropped, 8);
|
||||
|
||||
VkResult result = create(physical_device, ©, allocator, device);
|
||||
|
||||
relink(dropped, dropped_count);
|
||||
free(names);
|
||||
if (features2 && !info->pEnabledFeatures)
|
||||
features2->features = saved_features;
|
||||
if (robust)
|
||||
@@ -447,12 +575,15 @@ static VKAPI_ATTR VkResult VKAPI_CALL CreateDevice(VkPhysicalDevice physical_dev
|
||||
pthread_mutex_unlock(&global_lock);
|
||||
|
||||
if (requested) {
|
||||
layer_log("emulating%s%s%s%s%s%s for %s", (requested & GAP_FILL_MODE) ? " fillModeNonSolid" : "",
|
||||
layer_log("emulating%s%s%s%s%s%s%s%s%s for %s", (requested & GAP_FILL_MODE) ? " fillModeNonSolid" : "",
|
||||
(requested & GAP_MULTI_VIEWPORT) ? " multiViewport" : "",
|
||||
(requested & GAP_CLIP_DISTANCE) ? " shaderClipDistance" : "",
|
||||
(requested & GAP_CULL_DISTANCE) ? " shaderCullDistance" : "",
|
||||
(requested & GAP_ROBUSTNESS2) ? " robustBufferAccess2" : "",
|
||||
(requested & GAP_BC) ? " textureCompressionBC" : "", properties.deviceName);
|
||||
(requested & GAP_BC) ? " textureCompressionBC" : "",
|
||||
(requested & GAP_MULTI_DRAW) ? " multiDrawIndirect" : "",
|
||||
(requested & GAP_DEPTH_CLIP) ? " depthClipEnable" : "",
|
||||
(requested & GAP_NULL_DESCRIPTOR) ? " nullDescriptor" : "", properties.deviceName);
|
||||
}
|
||||
return VK_SUCCESS;
|
||||
}
|
||||
@@ -471,6 +602,7 @@ static VKAPI_ATTR void VKAPI_CALL DestroyDevice(VkDevice device, const VkAllocat
|
||||
if (!dev)
|
||||
return;
|
||||
bc_destroy_device(dev);
|
||||
null_resources_destroy(dev);
|
||||
dev->DestroyDevice(device, allocator);
|
||||
for (uint32_t i = 0; i < dev->shader_modules.capacity; i++) {
|
||||
struct spirv_code *code = dev->shader_modules.values[i];
|
||||
@@ -538,6 +670,22 @@ static const struct hook device_hooks[] = {
|
||||
HOOK(ResetCommandBuffer, GAP_BC),
|
||||
HOOK(ResetCommandPool, GAP_BC),
|
||||
HOOK(DestroyCommandPool, GAP_BC),
|
||||
HOOK(CmdDrawIndirect, GAP_MULTI_DRAW),
|
||||
HOOK(CmdDrawIndexedIndirect, GAP_MULTI_DRAW),
|
||||
HOOK(UpdateDescriptorSets, GAP_NULL_DESCRIPTOR),
|
||||
HOOK(CmdPushDescriptorSet, GAP_NULL_DESCRIPTOR),
|
||||
HOOK_ALIAS(CmdPushDescriptorSet, CmdPushDescriptorSetKHR, GAP_NULL_DESCRIPTOR),
|
||||
HOOK(CreateDescriptorUpdateTemplate, GAP_NULL_DESCRIPTOR),
|
||||
HOOK_ALIAS(CreateDescriptorUpdateTemplate, CreateDescriptorUpdateTemplateKHR, GAP_NULL_DESCRIPTOR),
|
||||
HOOK(DestroyDescriptorUpdateTemplate, GAP_NULL_DESCRIPTOR),
|
||||
HOOK_ALIAS(DestroyDescriptorUpdateTemplate, DestroyDescriptorUpdateTemplateKHR, GAP_NULL_DESCRIPTOR),
|
||||
HOOK(UpdateDescriptorSetWithTemplate, GAP_NULL_DESCRIPTOR),
|
||||
HOOK_ALIAS(UpdateDescriptorSetWithTemplate, UpdateDescriptorSetWithTemplateKHR, GAP_NULL_DESCRIPTOR),
|
||||
HOOK(CmdPushDescriptorSetWithTemplate, GAP_NULL_DESCRIPTOR),
|
||||
HOOK_ALIAS(CmdPushDescriptorSetWithTemplate, CmdPushDescriptorSetWithTemplateKHR, GAP_NULL_DESCRIPTOR),
|
||||
HOOK(CmdBindVertexBuffers, GAP_NULL_DESCRIPTOR),
|
||||
HOOK(CmdBindVertexBuffers2, GAP_NULL_DESCRIPTOR),
|
||||
HOOK_ALIAS(CmdBindVertexBuffers2, CmdBindVertexBuffers2EXT, GAP_NULL_DESCRIPTOR),
|
||||
};
|
||||
|
||||
static VKAPI_ATTR PFN_vkVoidFunction VKAPI_CALL GetDeviceProcAddr(VkDevice device, const char *name);
|
||||
@@ -562,6 +710,7 @@ static VKAPI_ATTR PFN_vkVoidFunction VKAPI_CALL GetDeviceProcAddr(VkDevice devic
|
||||
}
|
||||
|
||||
static const struct hook physical_device_hooks[] = {
|
||||
HOOK(EnumerateDeviceExtensionProperties, 0),
|
||||
HOOK(GetPhysicalDeviceFeatures, 0),
|
||||
HOOK(GetPhysicalDeviceFeatures2, 0),
|
||||
HOOK_ALIAS(GetPhysicalDeviceFeatures2, GetPhysicalDeviceFeatures2KHR, 0),
|
||||
|
||||
@@ -25,10 +25,14 @@ enum gap {
|
||||
GAP_CULL_DISTANCE = 1u << 3,
|
||||
GAP_ROBUSTNESS2 = 1u << 4,
|
||||
GAP_BC = 1u << 5,
|
||||
/* draw.c and pipeline.c (added for Mali-G57 and drivers without these, on top of David Cimo's six) */
|
||||
GAP_MULTI_DRAW = 1u << 6, /* multiDrawIndirect: indirect draws looped one by one */
|
||||
GAP_DEPTH_CLIP = 1u << 7, /* VK_EXT_depth_clip_enable: depthClipEnable off becomes depth clamp */
|
||||
GAP_NULL_DESCRIPTOR = 1u << 8, /* VK_EXT_robustness2 missing entirely: nullDescriptor stand-ins */
|
||||
};
|
||||
|
||||
#define GAPS_SHADER (GAP_CLIP_DISTANCE | GAP_CULL_DISTANCE)
|
||||
#define GAPS_PIPELINE (GAP_FILL_MODE | GAP_MULTI_VIEWPORT | GAPS_SHADER)
|
||||
#define GAPS_PIPELINE (GAP_FILL_MODE | GAP_MULTI_VIEWPORT | GAPS_SHADER | GAP_DEPTH_CLIP)
|
||||
|
||||
void layer_log(const char *format, ...) __attribute__((format(printf, 1, 2)));
|
||||
|
||||
@@ -109,7 +113,20 @@ struct instance {
|
||||
X(BeginCommandBuffer) \
|
||||
X(ResetCommandBuffer) \
|
||||
X(ResetCommandPool) \
|
||||
X(DestroyCommandPool)
|
||||
X(DestroyCommandPool) \
|
||||
X(CmdDrawIndirect) \
|
||||
X(CmdDrawIndexedIndirect) \
|
||||
X(GetImageMemoryRequirements) \
|
||||
X(BindImageMemory) \
|
||||
X(DestroyImageView) \
|
||||
X(UpdateDescriptorSets) \
|
||||
X(CmdPushDescriptorSet) \
|
||||
X(CreateDescriptorUpdateTemplate) \
|
||||
X(DestroyDescriptorUpdateTemplate) \
|
||||
X(UpdateDescriptorSetWithTemplate) \
|
||||
X(CmdPushDescriptorSetWithTemplate) \
|
||||
X(CmdBindVertexBuffers) \
|
||||
X(CmdBindVertexBuffers2)
|
||||
|
||||
struct staging_block;
|
||||
|
||||
@@ -132,6 +149,14 @@ struct device {
|
||||
struct handle_map memories; /* VkDeviceMemory -> struct mapped_memory */
|
||||
struct handle_map command_buffers; /* VkCommandBuffer -> struct command_buffer */
|
||||
struct staging_block *free_staging;
|
||||
struct handle_map templates; /* VkDescriptorUpdateTemplate -> struct template_info (draw.c) */
|
||||
/* nullDescriptor stand-ins (draw.c): 0 not made yet, 1 ready, -1 failed. */
|
||||
int null_ready;
|
||||
VkBuffer null_buffer;
|
||||
VkDeviceMemory null_buffer_memory;
|
||||
VkImage null_image;
|
||||
VkDeviceMemory null_image_memory;
|
||||
VkImageView null_view;
|
||||
struct device *next;
|
||||
};
|
||||
|
||||
@@ -243,4 +268,17 @@ struct instance *instance_from_handle(const void *dispatchable);
|
||||
/* What the GPU lacks of the features the layer can make up for. */
|
||||
uint32_t physical_device_gaps(struct instance *inst, VkPhysicalDevice physical_device);
|
||||
|
||||
|
||||
/* draw.c */
|
||||
VKAPI_ATTR void VKAPI_CALL CmdDrawIndirect(VkCommandBuffer cmd, VkBuffer buffer, VkDeviceSize offset, uint32_t draw_count, uint32_t stride);
|
||||
VKAPI_ATTR void VKAPI_CALL CmdDrawIndexedIndirect(VkCommandBuffer cmd, VkBuffer buffer, VkDeviceSize offset, uint32_t draw_count, uint32_t stride);
|
||||
VKAPI_ATTR void VKAPI_CALL UpdateDescriptorSets(VkDevice device, uint32_t write_count, const VkWriteDescriptorSet *writes, uint32_t copy_count, const VkCopyDescriptorSet *copies);
|
||||
VKAPI_ATTR void VKAPI_CALL CmdPushDescriptorSet(VkCommandBuffer cmd, VkPipelineBindPoint bind_point, VkPipelineLayout layout, uint32_t set, uint32_t write_count, const VkWriteDescriptorSet *writes);
|
||||
VKAPI_ATTR VkResult VKAPI_CALL CreateDescriptorUpdateTemplate(VkDevice device, const VkDescriptorUpdateTemplateCreateInfo *info, const VkAllocationCallbacks *allocator, VkDescriptorUpdateTemplate *tmpl);
|
||||
VKAPI_ATTR void VKAPI_CALL DestroyDescriptorUpdateTemplate(VkDevice device, VkDescriptorUpdateTemplate tmpl, const VkAllocationCallbacks *allocator);
|
||||
VKAPI_ATTR void VKAPI_CALL UpdateDescriptorSetWithTemplate(VkDevice device, VkDescriptorSet set, VkDescriptorUpdateTemplate tmpl, const void *data);
|
||||
VKAPI_ATTR void VKAPI_CALL CmdPushDescriptorSetWithTemplate(VkCommandBuffer cmd, VkDescriptorUpdateTemplate tmpl, VkPipelineLayout layout, uint32_t set, const void *data);
|
||||
VKAPI_ATTR void VKAPI_CALL CmdBindVertexBuffers(VkCommandBuffer cmd, uint32_t first, uint32_t count, const VkBuffer *buffers, const VkDeviceSize *offsets);
|
||||
VKAPI_ATTR void VKAPI_CALL CmdBindVertexBuffers2(VkCommandBuffer cmd, uint32_t first, uint32_t count, const VkBuffer *buffers, const VkDeviceSize *offsets, const VkDeviceSize *sizes, const VkDeviceSize *strides);
|
||||
void null_resources_destroy(struct device *dev);
|
||||
#endif
|
||||
@@ -87,6 +87,8 @@ static void find_stage_code(struct device *dev, const VkPipelineShaderStageCreat
|
||||
|
||||
struct pipeline_rewrite {
|
||||
VkPipelineRasterizationStateCreateInfo rasterization;
|
||||
/* VK_EXT_depth_clip_enable's state, taken out of the application's chain for the call. */
|
||||
VkBaseOutStructure *clip_prev, *clip_node;
|
||||
VkPipelineViewportStateCreateInfo viewport;
|
||||
VkPipelineShaderStageCreateInfo stages[MAX_STAGES];
|
||||
VkShaderModuleCreateInfo modules[MAX_STAGES];
|
||||
@@ -207,6 +209,29 @@ static void rewrite_pipeline(struct device *dev, VkGraphicsPipelineCreateInfo *i
|
||||
rw->rasterization.polygonMode = VK_POLYGON_MODE_FILL;
|
||||
info->pRasterizationState = &rw->rasterization;
|
||||
}
|
||||
/* No VK_EXT_depth_clip_enable: depth clipping off is the nearest the driver has as depth clamp. */
|
||||
if ((dev->emulated & GAP_DEPTH_CLIP) && info->pRasterizationState) {
|
||||
VkBaseOutStructure *prev = (VkBaseOutStructure *)info->pRasterizationState;
|
||||
while (prev->pNext && prev->pNext->sType != VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_DEPTH_CLIP_STATE_CREATE_INFO_EXT)
|
||||
prev = prev->pNext;
|
||||
VkBaseOutStructure *node = prev->pNext;
|
||||
if (node) {
|
||||
bool clip = ((VkPipelineRasterizationDepthClipStateCreateInfoEXT *)node)->depthClipEnable;
|
||||
if (info->pRasterizationState != &rw->rasterization) {
|
||||
rw->rasterization = *info->pRasterizationState;
|
||||
if (prev == (VkBaseOutStructure *)info->pRasterizationState)
|
||||
prev = (VkBaseOutStructure *)&rw->rasterization;
|
||||
info->pRasterizationState = &rw->rasterization;
|
||||
}
|
||||
if (!clip)
|
||||
rw->rasterization.depthClampEnable = VK_TRUE;
|
||||
if (prev != (VkBaseOutStructure *)&rw->rasterization) {
|
||||
rw->clip_prev = prev;
|
||||
rw->clip_node = node;
|
||||
}
|
||||
prev->pNext = node->pNext;
|
||||
}
|
||||
}
|
||||
if ((dev->emulated & GAP_MULTI_VIEWPORT) && info->pViewportState &&
|
||||
(info->pViewportState->viewportCount > 1 || info->pViewportState->scissorCount > 1)) {
|
||||
rw->viewport = *info->pViewportState;
|
||||
@@ -222,6 +247,8 @@ static void rewrite_pipeline(struct device *dev, VkGraphicsPipelineCreateInfo *i
|
||||
|
||||
static void undo_rewrite(struct device *dev, struct pipeline_rewrite *rw)
|
||||
{
|
||||
if (rw->clip_prev)
|
||||
rw->clip_prev->pNext = rw->clip_node;
|
||||
for (uint32_t i = 0; i < MAX_STAGES; i++) {
|
||||
if (rw->in_place[i]) {
|
||||
rw->in_place[i]->pCode = rw->in_place_code[i];
|
||||
|
||||
Reference in new issue
Block a user