Vulkan / OpenGL互操作计算着色器图像平铺问题

时间:2019-01-04 18:21:52

标签: glsl vulkan

我正在将Vulkan与GLSL计算着色器一起使用,以对在OpenGL中渲染的纹理进行后期处理。它在大多数情况下都可以正常工作,但是当纹理的垂直分辨率在一定范围内时,我会看到非常奇怪的异常,其中gl_GlobalInvocationID似乎被弄乱了。

一个示例计算着色器,演示了如下情况

Sub test()
 Dim user As String
 Dim pwd As String
 Dim path As String
 user = ""
 pwd = ""
 path = ""
 Debug.Print httpGET(path, user, pwd)
End Sub

Public Function httpGET(fn As String, _
        Optional authUser As String = vbNullString, _
        Optional authPass As String = vbNullString) As String
    pHtml = fn
    Dim oHttp As Object
    Set oHttp = CreateObject("Microsoft.XMLHTTP")
    Call oHttp.Open("GET", pHtml, False)
    If (authUser <> vbNullString) Then
    ' need to do basic authentication
    ' acknowledgement to http://pastie.org/1192157
        oHttp.SetRequestHeader "Content-Type", "application/json"
        oHttp.SetRequestHeader "Accept", "application/json"
        oHttp.SetRequestHeader "Authorization", "Basic " + _
            EncodeBase64(authUser + ":" + authPass)
    End If
    Call oHttp.Send("")
    httpGET = oHttp.ResponseText
    Set oHttp = Nothing
End Function


Function EncodeBase64(text As String) As String


  Dim arrData() As Byte
  arrData = StrConv(text, vbFromUnicode)

  Dim objXML As MSXML2.DOMDocument
  Dim objNode As MSXML2.IXMLDOMElement

  Set objXML = New MSXML2.DOMDocument
  Set objNode = objXML.createElement("b64")

  objNode.DataType = "bin.base64"
  objNode.nodeTypedValue = arrData
  EncodeBase64 = Application.Clean(objNode.text)

  Set objNode = Nothing
  Set objXML = Nothing
End Function

根据垂直分辨率,我得到奇怪的结果:482 +,241-256、121-128、55-64可以正常工作,但是257-481、129-240、65-121和<55不正确。见下文。

第482号垂直决议有效: 960x482 Working

垂直分辨率480损坏: 960x480 Not Working

我通过以下方式创建纹理:

#version 450
#extension GL_ARB_separate_shader_objects : enable

#define WORKGROUP_SIZE 32

layout(local_size_x=WORKGROUP_SIZE, local_size_y=WORKGROUP_SIZE, local_size_z=1) in;

layout(binding=0, rgba8) uniform image2D input_tex;
layout(binding=1, rgba8) uniform image2D output_tex;

void main()
{
    vec4 red = vec4(1.0, 0.0, 0.0, 1.0);
    vec4 black = vec4(0.0, 0.0, 0.0, 1.0);
    if(gl_GlobalInvocationID.x == 0 || gl_GlobalInvocationID.y == 0)
    {
        imageStore(output_tex, ivec2(gl_GlobalInvocationID.xy), red);
    }
    else
    {
        imageStore(output_tex, ivec2(gl_GlobalInvocationID.xy), black);
    }
}

我在OpenGL中渲染为纹理,然后使用vk::ImageCreateInfo image_create_info( vk::ImageCreateFlags(), vk::ImageType::e2D, vk::Format::eR8G8B8A8Unorm, {width, height, 1}, 1, 1, vk::SampleCountFlagBits::e1, vk::ImageTiling::eOptimal, vk::ImageUsageFlagBits::eColorAttachment | vk::ImageUsageFlagBits::eSampled | vk::ImageUsageFlagBits::eTransferSrc | vk::ImageUsageFlagBits::eStorage ); image = device.createImage(image_create_info); vk::MemoryRequirements memory_requirements = device.getImageMemoryRequirements(image); memory_size = memory_requirements.size; vk::ExportMemoryAllocateInfo export_allocate_info( vk::ExternalMemoryHandleTypeFlagBits::eOpaqueFd); vk::MemoryAllocateInfo memory_allocate_info( memory_size, memory_type // Standard way of finding this using eDeviceLocal ); memory_allocate_info.pNext = &export_allocate_info; device_memory = device.allocateMemory(memory_allocate_info); device.bindImageMemory(image, device_memory, 0); vk::MemoryGetFdInfoKHR memory_info(device_memory, vk::ExternalMemoryHandleTypeFlagBits::eOpaqueFd); opaque_handle = device.getMemoryFdKHR(memory_info, dynamic_loader); // Create OpenGL texture glCreateTextures(GL_TEXTURE_2D, 1, &opengl_tex); glCreateMemoryObjectsEXT(1, &opengl_memory); glImportMemoryFdEXT(opengl_memory, memory_size, GL_HANDLE_TYPE_OPAQUE_FD_EXT, opaque_handle); glTextureStorageMem2DEXT(opengl_tex, 1, GL_RGBA8, width, height, opengl_memory, 0); 从上方将渲染的图像复制到glBlitFramebuffer(0, 0, width, height, 0, 0, width, height, GL_COLOR_BUFFER_BIT, GL_NEAREST),然后执行包含上述着色器的命令缓冲区。之后,我将纹理回弹并在OpenGL中渲染到屏幕上。 (使用信号量进行同步)。

命令缓冲区的创建看起来像

opengl_tex

我检查了好几次,我并没有对某个地方的大小(除了工作组大小)进行硬编码。

我还制作了一个实用程序,可以读取png图像并执行相同的着色器并写出输出(绕过OpenGL互操作),并且无论尺寸大小都可以工作。

我需要能够处理480x480图像,因此我们将不胜感激。如果您需要其他任何信息,我可以提供更多代码。

(仅供参考,我在Linux和Vulkan 1.1.85.0上使用带有NVidia驱动程序410.78的GTX 1080)

编辑: 使用以下着色器代码段:

vk::CommandBufferBeginInfo begin_info(
    vk::CommandBufferUsageFlagBits());
command_buffer.begin(begin_info);
command_buffer.bindPipeline(vk::PipelineBindPoint::eCompute, pipeline);
command_buffer.bindDescriptorSets(vk::PipelineBindPoint::eCompute, pipeline_layout, 0, 1, &descriptor_set, 0, nullptr);
command_buffer.dispatch((uint32_t)ceil(width/float(WORKGROUP_SIZE), (uint32_t)ceil(height/float(WORKGROUP_SIZE)), 1);
command_buffer.end();

我得到结果

480x482图片工作:

480x482 Working

480x480图像损坏:

480x480 Broken

0 个答案:

没有答案