过去几周我一直在与Vulkan合作,而我遇到的问题只发生在AMD卡上.特别是AMD 7970M.我在GTX 700和900系列卡上运行我的项目没有问题.我甚至在Windows上运行了一个带有Nvidia卡的Linux(Steam OS).问题只出现在AMD卡上,只出现在我的项目中; 来自Sascha Willems的所有样品和项目都没有问题.
现在我正在绘制纹理Raptor模型并将其旋转到位.我将其渲染到纹理,然后将该纹理应用于全屏三角形; 基本的屏幕外渲染.但是我的7970M上的深度似乎没有正确清晰.相反,我得到这个奇怪的神器,就像深度未被正确清除:

当然我试着用RenderDoc挖掘它,深度是完全错误的.Raptor和Fullscreen Triangle都是一团糟:


我已经尝试将我的代码与Sascha Willems的Offscreen示例进行比较,我看起来几乎都以同样的方式做了一切.我想也许我创建深度的方式可能有问题,但与我见过的所有例子相比,这似乎很好.
以下是我创建深度图像和视图的一些调试视图:

这是整个方法:
bool VKRenderTarget::setupFramebuffer(VKRenderer* renderer)
{
VkDevice device = renderer->GetVKDevice();
VkCommandBuffer setupCommand;
m_colorFormat = renderer->GetPreferredImageFormat();
m_depthFormat = renderer->GetPreferredDepthFormat();
renderer->CreateSetupCommandBuffer();
setupCommand = renderer->GetSetupCommandBuffer();
VkResult err;
//Color attachment
VkImageCreateInfo imageInfo = {};
imageInfo.sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO;
imageInfo.pNext = nullptr;
imageInfo.format = m_colorFormat;
imageInfo.imageType = VK_IMAGE_TYPE_2D;
imageInfo.extent.width = m_width;
imageInfo.extent.height = m_height;
imageInfo.mipLevels = 1;
imageInfo.arrayLayers = 1;
imageInfo.samples = VK_SAMPLE_COUNT_1_BIT;
imageInfo.tiling = VK_IMAGE_TILING_OPTIMAL;
imageInfo.usage = VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | VK_IMAGE_USAGE_TRANSFER_SRC_BIT;
imageInfo.flags …Run Code Online (Sandbox Code Playgroud) 在我的机器上,我有两个队列系列,一个支持所有内容,另一个支持转移.
支持所有内容的队列系列的queueCount为16.
现在规范说明了
提交给不同队列的命令缓冲区可以相互并行地执行,甚至可以不按顺序执行
这是否意味着我应该尝试使用所有可用的队列以获得最佳性能?
Khronos刚刚发布了他们的新内存模型扩展,但还没有进行非正式讨论,示例实现等等,所以我对基本细节感到困惑.
https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#memory-model
这些新扩展试图准确解决什么?他们是在尝试解决语言级别的同步问题(比如在C++代码中删除繁琐的互斥体),还是一组新的复杂功能,让您可以更好地控制GPU如何在内部处理同步?
(推测性问题)在一般情况下学习和合并这个新模型是不是一个好主意,或者这个模型是否只适用于某些多线程模式并可能增加开销?
在Imagination网站上的文章中,我读过以下段落:
例如,
glUniform*()Vulkan 中没有等效的入口点; 相反,写入GPU内存是将数据传递到着色器的唯一方法.当您调用时
glUniform*(),OpenGL ES驱动程序通常需要分配驱动程序托管缓冲区并将数据复制到其中,其管理会产生CPU开销.在Vulkan中,您只需映射内存地址并直接写入该内存位置.
它与使用统一缓冲区之间有什么区别吗?它们也是明确分配的,可以携带任意数据.由于Uniform Buffers的大小非常有限,因此Shader Storage Buffers可能是一个更好的类比.
在 Ubuntu 中创建新的 Android 模拟器时显示以下错误,这会影响我的 vulkan 游戏开发吗?
queryCoreProfileSupport: swap interval not found
emulator: ERROR: VkCommonOperations.cpp:496: Failed to create Vulkan instance.
emulator: WARNING: Ignoring invalid http proxy: Bad format: invalid port number (must be decimal)
Run Code Online (Sandbox Code Playgroud)
下面添加了我的 AVD 设备规范。
我想弄清楚,但我有点陷入困境.
类型和堆相关的方式很简单,如果有点奇怪.(为什么不给VkMemoryHeap一个VkMemoryType会员?)
我想我明白了所有的VkMemoryPropertyFlags意思,它们看起来相当简单.
但是VkMemoryHeap.flags会员呢?它显然只有一个非零有效值,VkMemoryHeapFlagBits.VK_MEMORY_HEAP_DEVICE_LOCAL_BIT虽然它本身不会太奇怪,但也有一个VkMemoryPropertyFlagBits.VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT可能出现在堆的内存类型上.
VkMemoryHeap.flags会员意味着什么以及它与VkMemoryType.flags会员有什么关系?
我有一个顶点着色器,其中包含一个包含一个浮点数的push-constant块:
layout(push_constant) uniform pushConstants {
float test1;
} u_pushConstants;
Run Code Online (Sandbox Code Playgroud)
一个片段着色器与另一个具有不同浮点值的push-constant块:
layout(push_constant) uniform pushConstants {
float test2;
} u_pushConstants;
Run Code Online (Sandbox Code Playgroud)
test1和test2应该是不同的.
管道布局的推 - 常量范围定义如下:
std::array<vk::PushConstantRange,2> ranges = {
vk::PushConstantRange{
vk::ShaderStageFlagBits::eVertex,
0,
sizeof(float)
},
vk::PushConstantRange{
vk::ShaderStageFlagBits::eFragment,
sizeof(float), // Push-constant range offset (Start after vertex push constants)
sizeof(float)
}
};
Run Code Online (Sandbox Code Playgroud)
然后在渲染过程中推送实际常量,如下所示:
std::array<float,1> constants = {123.f};
commandBufferDraw.pushConstants(
pipelineLayout,
vk::ShaderStageFlagBits::eVertex,
0,
sizeof(float),
constants.data()
);
std::array<float,1> constants = {456.f};
commandBufferDraw.pushConstants(
pipelineLayout,
vk::ShaderStageFlagBits::eFragment,
sizeof(float), // Offset in bytes
sizeof(float),
constants.data()
);
Run Code Online (Sandbox Code Playgroud)
但是,在检查着色器内部的值时,两者都具有值123.似乎完全忽略了偏移量.我不正确地使用它们吗?
我知道framebuffer是渲染管道的最终目的地,而swapchain包含许多图像.那么这两件事之间的关系是什么?哪一个是实际的渲染目标?帧缓冲区后来是否会在图像视图中附加当前帧的最终图片?如果是这样,它将如何转移?
通过油漆或图表描述这一点会很高兴.
从规格:
VK_KHR_maintenance1
允许在slink :: VkViewport :: height字段中指定负高度,以执行剪辑空间到帧缓冲区空间变换的y反转.这样,应用就可以避免在着色器中使用gl_Position.y = -gl_Position.y,同时针对其他API.
我的物理设备支持版本1.0.42,我启用了VK_KHR_maintenance1.当我在VkViewport结构中执行负高度时,我没有得到任何验证错误/警告.
vkCmdSetViewport(vkContext.commandBuffer, 0, 1, &viewport);
Run Code Online (Sandbox Code Playgroud)
但是我在屏幕上看不到任何东西,它的黑色,如果我删除viewport所有内容中的负值都按预期呈现.我是否需要做任何其他事情来翻转视口VK_KHR_maintenance1 extension?我只是在屏幕上渲染一个红色四边形,带有全屏视口.
VkViewport viewport = {};
viewport.x = 0.0f;
viewport.y = 0.0f;
viewport.width = 1024.0f;
viewport.height = -1024.0f;
viewport.minDepth = 0.0f;
viewport.maxDepth = 1.0f;
vkCmdSetViewport(vkContext.commandBuffer, 0, 1, &viewport);
Run Code Online (Sandbox Code Playgroud)
顶点着色器:
void main() {
vec4 positions[3] = {
vec4(-1.0, -1.0, 0.0, 1.0),
vec4(3.0, -1.0, 0.0, 1.0),
vec4(-1.0, 3.0, 0.0, 1.0)
};
gl_Position = positions[gl_VertexIndex % 3];
}
Run Code Online (Sandbox Code Playgroud)
片段着色器: …
关于Vulkan API,"附件"是什么意思?我看到与渲染通道相关的单词(即:颜色附件).我对我认为它们的含义模糊不清,但我想听听专家的定义.
我是第一次进行图形编程,并决定从Vulkan开始直接进入深层.