浏览代码

vulkan: Support ShaderPtrSpec (numeric) shader inputs

Probably want to rethink whether these should be put under the ShaderAttrib descriptor set and updated less frequently, but this works for now
rdb 5 年之前
父节点
当前提交
98467caf9e
共有 1 个文件被更改,包括 115 次插入2 次删除
  1. 115 2
      panda/src/vulkandisplay/vulkanShaderContext.cxx

+ 115 - 2
panda/src/vulkandisplay/vulkanShaderContext.cxx

@@ -406,8 +406,121 @@ update_uniform_buffers(VulkanGraphicsStateGuardian *gsg, int altered) {
     ++count;
   }
 
-  //TODO: ptr inputs
-  _uniform_offsets[count] = 0;
+  // We have no way to track modifications to PTAs, so we assume that they are
+  // modified every frame and when we switch ShaderAttribs.
+  if (_ptr_block_size > 0 &&
+      (altered & (Shader::SSD_shaderinputs | Shader::SSD_frame)) != 0) {
+    void *ptr = alloca(_ptr_block_size);
+
+    size_t i = 0;
+    for (Shader::ShaderPtrSpec &spec : _shader->_ptr_spec) {
+      Shader::ShaderPtrData ptr_data;
+      if (!gsg->fetch_ptr_parameter(spec, ptr_data)) {
+        continue;
+      }
+
+      nassertd(spec._dim[1] > 0) continue;
+
+      uint32_t dim = spec._dim[1] * spec._dim[2];
+
+      uint32_t offset = _ptr_block_type->get_member(i++).offset;
+      void *dest = (void *)((char *)ptr + offset);
+
+      int array_size = std::min(spec._dim[0], (uint32_t)(ptr_data._size / dim));
+      switch (spec._type) {
+      case ShaderType::ST_bool:
+      case ShaderType::ST_float:
+        {
+          float *data = (float *)dest;
+
+          switch (ptr_data._type) {
+          case ShaderType::ST_int:
+            // Convert int data to float data.
+            for (int i = 0; i < (array_size * dim); ++i) {
+              data[i] = (float)(((int*)ptr_data._ptr)[i]);
+            }
+            break;
+
+          case ShaderType::ST_uint:
+            // Convert unsigned int data to float data.
+            for (int i = 0; i < (array_size * dim); ++i) {
+              data[i] = (float)(((unsigned int*)ptr_data._ptr)[i]);
+            }
+            break;
+
+          case ShaderType::ST_double:
+            // Downgrade double data to float data.
+            for (int i = 0; i < (array_size * dim); ++i) {
+              data[i] = (float)(((double*)ptr_data._ptr)[i]);
+            }
+            break;
+
+          case ShaderType::ST_float:
+            memcpy(data, ptr_data._ptr, array_size * dim * sizeof(float));
+            break;
+
+          default:
+            nassertd(false) continue;
+          }
+        }
+        break;
+
+      case ShaderType::ST_int:
+      case ShaderType::ST_uint:
+        if (ptr_data._type != ShaderType::ST_int &&
+            ptr_data._type != ShaderType::ST_uint) {
+          vulkandisplay_cat.error()
+            << "Cannot pass floating-point data to integer shader input '" << spec._id._name << "'\n";
+
+        } else {
+          memcpy(dest, ptr_data._ptr, array_size * dim * sizeof(int));
+          nassertd(false) continue;
+        }
+        break;
+
+      case ShaderType::ST_double:
+        {
+          double *data = (double *)dest;
+
+          switch (ptr_data._type) {
+          case ShaderType::ST_int:
+            // Convert int data to double data.
+            for (int i = 0; i < (array_size * dim); ++i) {
+              data[i] = (double)(((int*)ptr_data._ptr)[i]);
+            }
+            break;
+
+          case ShaderType::ST_uint:
+            // Convert unsigned int data to double data.
+            for (int i = 0; i < (array_size * dim); ++i) {
+              data[i] = (double)(((unsigned int*)ptr_data._ptr)[i]);
+            }
+            break;
+
+          case ShaderType::ST_double:
+            memcpy(data, ptr_data._ptr, array_size * dim * sizeof(double));
+            break;
+
+          case ShaderType::ST_float:
+            // Upgrade float data to double data.
+            for (int i = 0; i < (array_size * dim); ++i) {
+              data[i] = (double)(((double*)ptr_data._ptr)[i]);
+            }
+            break;
+
+          default:
+            nassertd(false) continue;
+          }
+        }
+        break;
+
+      default:
+        continue;
+      }
+    }
+
+    _uniform_offsets[count] = gsg->update_dynamic_uniform_buffer(ptr, _mat_block_size);
+  }
 }
 
 /**