Просмотр исходного кода

OpenGL: Added support for shared storage blocks

BearishSun 9 лет назад
Родитель
Сommit
718ed85258

+ 19 - 10
Source/BansheeGLRenderAPI/Source/BsGLGpuBuffer.cpp

@@ -11,8 +11,8 @@ namespace bs { namespace ct
 	GLGpuBuffer::GLGpuBuffer(const GPU_BUFFER_DESC& desc, GpuDeviceFlags deviceMask)
 		: GpuBuffer(desc, deviceMask), mTextureID(0), mFormat(0)
 	{
-		if(desc.type != GBT_STANDARD)
-			LOGERR("Only standard buffers are support on OpenGL.");
+		if(desc.type == GBT_APPENDCONSUME || desc.type == GBT_INDIRECTARGUMENT || desc.type == GBT_RAW)
+			LOGERR("Only standard and structured buffers are supported on OpenGL.");
 
 		if (desc.useCounter)
 			LOGERR("Buffer counters not supported on OpenGL.");
@@ -35,14 +35,23 @@ namespace bs { namespace ct
 	void GLGpuBuffer::initialize()
 	{
 		// Create buffer
-		const auto& props = getProperties();
-		UINT32 size = props.getElementCount() * props.getElementSize();
-		mBuffer.initialize(GL_TEXTURE_BUFFER, size, props.getUsage());
-		
-		// Create texture
-		glGenTextures(1, &mTextureID);
-		glBindTexture(GL_TEXTURE_BUFFER, mTextureID);
-		glTexBuffer(GL_TEXTURE_BUFFER, mFormat, mBuffer.getGLBufferId());
+		if(mProperties.getType() == GBT_STRUCTURED)
+		{
+			const auto& props = getProperties();
+			UINT32 size = props.getElementCount() * props.getElementSize();
+			mBuffer.initialize(GL_SHADER_STORAGE_BUFFER, size, props.getUsage());
+		}
+		else
+		{
+			const auto& props = getProperties();
+			UINT32 size = props.getElementCount() * props.getElementSize();
+			mBuffer.initialize(GL_TEXTURE_BUFFER, size, props.getUsage());
+
+			// Create texture
+			glGenTextures(1, &mTextureID);
+			glBindTexture(GL_TEXTURE_BUFFER, mTextureID);
+			glTexBuffer(GL_TEXTURE_BUFFER, mFormat, mBuffer.getGLBufferId());
+		}
 
 		BS_INC_RENDER_STAT_CAT(ResCreated, RenderStatObject_GpuBuffer);
 		GpuBuffer::initialize();

+ 73 - 36
Source/BansheeGLRenderAPI/Source/BsGLRenderAPI.cpp

@@ -405,6 +405,22 @@ namespace bs { namespace ct
 					return unit;
 				};
 
+				UINT32 sharedStorageUnitCount = 0;
+				FrameVector<UINT32> sharedStorageUnits(6);
+				auto getSharedStorageUnit = [&](UINT32 binding)
+				{
+					for (UINT32 i = 0; i < (UINT32)sharedStorageUnits.size(); i++)
+					{
+						if (sharedStorageUnits[i] == binding)
+							return i;
+					}
+
+					UINT32 unit = sharedStorageUnitCount++;
+					sharedStorageUnits.push_back(binding);
+
+					return unit;
+				};
+
 				const UINT32 numStages = 6;
 				for(UINT32 i = 0; i < numStages; i++)
 				{
@@ -488,54 +504,76 @@ namespace bs { namespace ct
 						UINT32 binding = entry.second.slot;
 						SPtr<GpuBuffer> buffer = gpuParams->getBuffer(entry.second.set, binding);
 
-						bool isLoadStore = entry.second.type != GPOT_BYTE_BUFFER &&
-							entry.second.type != GPOT_STRUCTURED_BUFFER;
-
 						GLGpuBuffer* glBuffer = static_cast<GLGpuBuffer*>(buffer.get());
-						if (!isLoadStore)
-						{
-							UINT32 unit = getTexUnit(binding);
-							if (!activateGLTextureUnit(unit))
-								continue;
 
-							if (glBuffer != nullptr)
+						switch(entry.second.type)
+						{
+						case GPOT_BYTE_BUFFER: // Texture buffer (read-only, unstructured)
 							{
-								if (mTextureInfos[unit].type != GL_TEXTURE_BUFFER)
-									glBindTexture(mTextureInfos[unit].type, 0);
+								UINT32 unit = getTexUnit(binding);
+								if (!activateGLTextureUnit(unit))
+									continue;
 
-								mTextureInfos[unit].type = GL_TEXTURE_BUFFER;
+								if (glBuffer != nullptr)
+								{
+									if (mTextureInfos[unit].type != GL_TEXTURE_BUFFER)
+										glBindTexture(mTextureInfos[unit].type, 0);
 
-								glBindTexture(GL_TEXTURE_BUFFER, glBuffer->getGLTextureId());
+									mTextureInfos[unit].type = GL_TEXTURE_BUFFER;
 
-								SPtr<GLSLGpuProgram> activeProgram = getActiveProgram(type);
-								if (activeProgram != nullptr)
-								{
-									GLuint glProgram = activeProgram->getGLHandle();
+									glBindTexture(GL_TEXTURE_BUFFER, glBuffer->getGLTextureId());
 
-									glProgramUniform1i(glProgram, binding, unit);
+									SPtr<GLSLGpuProgram> activeProgram = getActiveProgram(type);
+									if (activeProgram != nullptr)
+									{
+										GLuint glProgram = activeProgram->getGLHandle();
+
+										glProgramUniform1i(glProgram, binding, unit);
+									}
 								}
+								else
+									glBindTexture(mTextureInfos[unit].type, 0);
 							}
-							else
-								glBindTexture(mTextureInfos[unit].type, 0);
-						}
-						else
-						{
-							UINT32 unit = getImageUnit(binding);
-							if (glBuffer != nullptr)
+							break;
+						case GPOT_RWBYTE_BUFFER: // Storage buffer (read/write, unstructured)
 							{
-								glBindImageTexture(unit, glBuffer->getGLTextureId(), 0, false,
-									0, GL_READ_WRITE, glBuffer->getGLFormat());
-
-								SPtr<GLSLGpuProgram> activeProgram = getActiveProgram(type);
-								if (activeProgram != nullptr)
+								UINT32 unit = getImageUnit(binding);
+								if (glBuffer != nullptr)
 								{
-									GLuint glProgram = activeProgram->getGLHandle();
+									glBindImageTexture(unit, glBuffer->getGLTextureId(), 0, false,
+													   0, GL_READ_WRITE, glBuffer->getGLFormat());
 
-									glProgramUniform1i(glProgram, binding, unit);
+									SPtr<GLSLGpuProgram> activeProgram = getActiveProgram(type);
+									if (activeProgram != nullptr)
+									{
+										GLuint glProgram = activeProgram->getGLHandle();
+
+										glProgramUniform1i(glProgram, binding, unit);
+									}
+								}
+								else
+									glBindImageTexture(unit, 0, 0, false, 0, GL_READ_WRITE, GL_R32F);
+							}
+							break;
+						case GPOT_RWSTRUCTURED_BUFFER: // Shared storage block (read/write, structured)
+							{
+								UINT32 unit = getSharedStorageUnit(binding);
+								if (glBuffer != nullptr)
+								{
+									glBindBufferBase(GL_SHADER_STORAGE_BUFFER, unit, glBuffer->getGLBufferId());
+									
+									SPtr<GLSLGpuProgram> activeProgram = getActiveProgram(type);
+									if (activeProgram != nullptr)
+									{
+										GLuint glProgram = activeProgram->getGLHandle();
+
+										glShaderStorageBlockBinding(glProgram, binding, unit);
+									}
 								}
+								else
+									glBindBufferBase(GL_SHADER_STORAGE_BUFFER, unit, 0);
 							}
-							else
-								glBindImageTexture(unit, 0, 0, false, 0, GL_READ_WRITE, GL_R32F);
+							break;
 						}
 					}
 
@@ -677,8 +715,7 @@ namespace bs { namespace ct
 
 							UINT32 unit = getUniformUnit(binding - 1);
 							glUniformBlockBinding(glProgram, binding - 1, unit);
-							glBindBufferRange(GL_UNIFORM_BUFFER, unit, glParamBlockBuffer->getGLHandle(), 0,
-								glParamBlockBuffer->getSize());
+							glBindBufferBase(GL_UNIFORM_BUFFER, unit, glParamBlockBuffer->getGLHandle());
 						}
 					}
 				}

+ 37 - 13
Source/BansheeGLRenderAPI/Source/BsGLSLParamParser.cpp

@@ -124,15 +124,18 @@ namespace bs { namespace ct
 
 	void GLSLParamParser::buildUniformDescriptions(GLuint glProgram, GpuProgramType type, GpuParamDesc& returnParamDesc)
 	{
-		// scan through the active uniforms and add them to the reference list
+		// Scan through the active uniform blocks
 		GLint maxBufferSize = 0;
 		glGetProgramiv(glProgram, GL_ACTIVE_UNIFORM_MAX_LENGTH, &maxBufferSize);
 
 		GLint maxBlockNameBufferSize = 0;
 		glGetProgramiv(glProgram, GL_ACTIVE_UNIFORM_BLOCK_MAX_NAME_LENGTH, &maxBlockNameBufferSize);
 
-		if (maxBlockNameBufferSize > maxBufferSize)
-			maxBufferSize = maxBlockNameBufferSize;
+		GLint maxStorageBlockNameBufferSize = 0;
+		glGetProgramInterfaceiv(glProgram, GL_SHADER_STORAGE_BLOCK, GL_MAX_NAME_LENGTH, &maxStorageBlockNameBufferSize);
+
+		maxBufferSize = std::max(maxBufferSize, maxBlockNameBufferSize);
+		maxBufferSize = std::max(maxBufferSize, maxStorageBlockNameBufferSize);
 
 		GLchar* uniformName = (GLchar*)bs_alloc(sizeof(GLchar)* maxBufferSize);
 
@@ -147,14 +150,14 @@ namespace bs { namespace ct
 		GpuParamBlockDesc& globalBlockDesc = returnParamDesc.paramBlocks[newGlobalBlockDesc.name];
 
 		GLint uniformBlockCount = 0;
-		glGetProgramiv(glProgram, GL_ACTIVE_UNIFORM_BLOCKS, &uniformBlockCount);
+		glGetProgramInterfaceiv(glProgram, GL_UNIFORM_BLOCK, GL_ACTIVE_RESOURCES, &uniformBlockCount);
 
 		Map<UINT32, String> blockSlotToName;
 		Set<String> blockNames;
 		for (GLuint index = 0; index < (GLuint)uniformBlockCount; index++)
 		{
 			GLsizei unusedSize = 0;
-			glGetActiveUniformBlockName(glProgram, index, maxBufferSize, &unusedSize, uniformName);
+			glGetProgramResourceName(glProgram, GL_UNIFORM_BLOCK, index, maxBufferSize, &unusedSize, uniformName);
 
 			GpuParamBlockDesc newBlockDesc;
 			newBlockDesc.slot = index + 1;
@@ -164,14 +167,32 @@ namespace bs { namespace ct
 			newBlockDesc.isShareable = true;
 
 			returnParamDesc.paramBlocks[newBlockDesc.name] = newBlockDesc;
-			blockSlotToName.insert(std::make_pair(newBlockDesc.slot, newBlockDesc.name));
+			blockSlotToName.insert(std::make_pair(index + 1, newBlockDesc.name));
 			blockNames.insert(newBlockDesc.name);
 		}
 
+		// Scan through the shared storage blocks
+		GLint storageBlockCount = 0;
+		glGetProgramInterfaceiv(glProgram, GL_SHADER_STORAGE_BLOCK, GL_ACTIVE_RESOURCES, &storageBlockCount);
+
+		for (GLuint index = 0; index < (GLuint)storageBlockCount; index++)
+		{
+			GLsizei unusedSize = 0;
+			glGetProgramResourceName(glProgram, GL_SHADER_STORAGE_BLOCK, index, maxBufferSize, &unusedSize, uniformName);
+
+			GpuParamObjectDesc bufferParam;
+			bufferParam.name = uniformName;
+			bufferParam.slot = index;
+			bufferParam.type = GPOT_RWSTRUCTURED_BUFFER;
+			bufferParam.set = mapParameterToSet(type, ParamType::StorageBlock);
+
+			returnParamDesc.buffers.insert(std::make_pair(uniformName, bufferParam));
+		}
+
 		Map<String, UINT32> foundFirstArrayIndex;
 		Map<String, GpuParamDataDesc> foundStructs;
 
-		// get the number of active uniforms
+		// Get the number of active uniforms
 		GLint uniformCount = 0;
 		glGetProgramiv(glProgram, GL_ACTIVE_UNIFORMS, &uniformCount);
 
@@ -386,12 +407,12 @@ namespace bs { namespace ct
 
 				if (uniformType == GL_IMAGE_BUFFER)
 				{
-					bufferParam.type = GPOT_RWSTRUCTURED_BUFFER;
+					bufferParam.type = GPOT_RWBYTE_BUFFER;
 					bufferParam.set = mapParameterToSet(type, ParamType::Image);
 				}
 				else // Sampler buffer
 				{
-					bufferParam.type = GPOT_STRUCTURED_BUFFER;
+					bufferParam.type = GPOT_BYTE_BUFFER;
 					bufferParam.set = mapParameterToSet(type, ParamType::Texture);
 				}
 
@@ -423,12 +444,12 @@ namespace bs { namespace ct
 					blockOffset = blockOffset / 4;
 
 					gpuParam.gpuMemOffset = blockOffset;
-					gpuParam.paramBlockSlot = blockIndex + 1; // 0 is reserved for globals
-					gpuParam.paramBlockSet = mapParameterToSet(type, ParamType::UniformBlock);
 
-					String& blockName = blockSlotToName[gpuParam.paramBlockSlot];
+					String& blockName = blockSlotToName[blockIndex + 1];
 					GpuParamBlockDesc& curBlockDesc = returnParamDesc.paramBlocks[blockName];
 
+					gpuParam.paramBlockSlot = curBlockDesc.slot;
+					gpuParam.paramBlockSet = mapParameterToSet(type, ParamType::UniformBlock);
 					gpuParam.cpuMemOffset = blockOffset;
 					curBlockDesc.blockSize = std::max(curBlockDesc.blockSize, gpuParam.cpuMemOffset + gpuParam.arrayElementStride * gpuParam.arraySize);
 				}
@@ -503,19 +524,22 @@ namespace bs { namespace ct
 
 #if BS_DEBUG_MODE
 		// Check if manually calculated and OpenGL buffer sizes match
+		UINT32 blockIdx = 0;
 		for (auto iter = returnParamDesc.paramBlocks.begin(); iter != returnParamDesc.paramBlocks.end(); ++iter)
 		{
 			if (iter->second.slot == 0)
 				continue;
 
 			GLint blockSize = 0;
-			glGetActiveUniformBlockiv(glProgram, iter->second.slot - 1, GL_UNIFORM_BLOCK_DATA_SIZE, &blockSize);
+			glGetActiveUniformBlockiv(glProgram, blockIdx, GL_UNIFORM_BLOCK_DATA_SIZE, &blockSize);
 
 			assert(blockSize % 4 == 0);
 			blockSize = blockSize / 4;
 
 			if (iter->second.blockSize != blockSize)
 				BS_EXCEPT(InternalErrorException, "OpenGL specified and manual uniform block buffer sizes don't match!");
+
+			blockIdx++;
 		}
 #endif
 

+ 1 - 0
Source/BansheeGLRenderAPI/Source/GLSL/include/BsGLSLParamParser.h

@@ -67,6 +67,7 @@ namespace bs { namespace ct
 			Texture,
 			Sampler,
 			Image,
+			StorageBlock,
 			Count // Keep at end
 		};
 

+ 2 - 2
Source/BansheeVulkanRenderAPI/Source/BsVulkanGpuProgram.cpp

@@ -448,7 +448,7 @@ namespace bs { namespace ct
 					case glslang::Esd1D:		param.type = GPOT_RWTEXTURE1D; break;
 					case glslang::Esd2D:		param.type = sampler.isMultiSample() ? GPOT_RWTEXTURE2DMS : GPOT_RWTEXTURE2D; break;
 					case glslang::Esd3D:		param.type = GPOT_RWTEXTURE3D; break;
-					case glslang::EsdBuffer:	param.type = GPOT_RWSTRUCTURED_BUFFER; break;
+					case glslang::EsdBuffer:	param.type = GPOT_RWBYTE_BUFFER; break;
 					}
 
 					if(sampler.dim != glslang::EsdBuffer)
@@ -476,7 +476,7 @@ namespace bs { namespace ct
 						case glslang::Esd2D:		param.type = sampler.isMultiSample() ? GPOT_TEXTURE2DMS : GPOT_TEXTURE2D; break;
 						case glslang::Esd3D:		param.type = GPOT_TEXTURE3D; break;
 						case glslang::EsdCube:		param.type = GPOT_TEXTURECUBE; break;
-						case glslang::EsdBuffer:	param.type = GPOT_STRUCTURED_BUFFER; break;
+						case glslang::EsdBuffer:	param.type = GPOT_BYTE_BUFFER; break;
 						}
 
 						if (sampler.dim != glslang::EsdBuffer)