Răsfoiți Sursa

metal (#855)

- msaa framebuffer
- capture (wip)
- read_back
- 30-picking fixes
attilaz 9 ani în urmă
părinte
comite
9d6364e6ee
2 a modificat fișierele cu 189 adăugiri și 36 ștergeri
  1. 6 4
      src/renderer_mtl.h
  2. 183 32
      src/renderer_mtl.mm

+ 6 - 4
src/renderer_mtl.h

@@ -438,7 +438,7 @@ namespace bgfx { namespace mtl
 		}
 
 		// Copying Data from a Texture Image
-		void getBytes(void* _pixelBytes, NSUInteger _bytesPerRow, NSUInteger _bytesPerImage, MTLRegion _region, NSUInteger _mipmapLevel, NSUInteger _slice)
+		void getBytes(void* _pixelBytes, NSUInteger _bytesPerRow, NSUInteger _bytesPerImage, MTLRegion _region, NSUInteger _mipmapLevel, NSUInteger _slice) const
 		{
 			[m_obj getBytes:_pixelBytes bytesPerRow:_bytesPerRow bytesPerImage:_bytesPerImage fromRegion:_region mipmapLevel:_mipmapLevel slice:_slice];
 		}
@@ -450,12 +450,12 @@ namespace bgfx { namespace mtl
 		}
 
 		//properties
-		uint32_t width()
+		uint32_t width() const
 		{
 			return (uint32_t)m_obj.width;
 		}
 
-		uint32_t height()
+		uint32_t height() const
 		{
 			return (uint32_t)m_obj.height;
 		}
@@ -465,7 +465,7 @@ namespace bgfx { namespace mtl
 			return m_obj.pixelFormat;
 		}
 
-		uint32_t sampleCount()
+		uint32_t sampleCount() const
 		{
 			return (uint32_t)m_obj.sampleCount;
 		}
@@ -736,6 +736,7 @@ namespace bgfx { namespace mtl
 	{
 		TextureMtl()
 			: m_ptr(NULL)
+			, m_ptrMSAA(NULL)
 			, m_ptrStencil(NULL)
 			, m_sampler(NULL)
 			, m_flags(0)
@@ -756,6 +757,7 @@ namespace bgfx { namespace mtl
 		void commit(uint8_t _stage, uint32_t _flags = BGFX_TEXTURE_INTERNAL_DEFAULT_SAMPLER);
 
 		Texture m_ptr;
+		Texture m_ptrMSAA;
 		Texture m_ptrStencil; // for emulating packed depth/stencil formats - only for iOS8...
 		SamplerState m_sampler;
 		uint32_t m_flags;

+ 183 - 32
src/renderer_mtl.mm

@@ -30,6 +30,10 @@
 	  packFloatToRGBA needs highp. currently it uses half.
    24-nbody: no generated compute shaders for metal
    27-terrain: shaderc generates invalid metal shader for vs_terrain_height_texture. vertex output: half4 gl_Position [[position]], should be float4
+   31-rsm:
+      <program source>:6:23: error: type 'half4' (aka 'vector_half4') is not valid for attribute 'position'
+      half4 gl_Position [[position]];
+
 
 Known issues(driver problems??):
   OSX mac mini(late 2014), OSX10.11.3 : nanovg-rendering: color writemask off causes problem...
@@ -40,16 +44,18 @@ Known issues(driver problems??):
 			Only on this device ( no problem on iPad Air 2 with iOS9.3.1)
 
   TODOs:
- - texture msaa: 09-hdr
- - texture blit+read_back: 09-hdr
- - textureMtl::commit set only vertex/fragment stage
- - FrameBufferMtl::postReset recreate framebuffer???
- - implement fb discard. problematic with multiple views that has same fb...
  - remove sync points at texture/mesh update
- - capture: 07-callback
+ 
+ - textureMtl::commit set only vertex/fragment stage
 
- - backbuffer msaa color/depth/stencil is not saved. could have problem with views like: backbuffermsaa then rt then backbuffermsaa again
+ - FrameBufferMtl::postReset recreate framebuffer???
 
+	renderpass load/resolve
+ - capture with msaa: 07-callback
+ - implement fb discard. problematic with multiple views that has same fb...
+ - msaa color/depth/stencil is not saved. could have problem when we switch back to msaa framebuffer
+ - refactor store/load actions to support msaa/discard/capture/readback etc...
+ 
  - finish savescreenshot with screenshotbegin/end
 
  - support multiple windows: 22-windows
@@ -350,6 +356,8 @@ namespace bgfx { namespace mtl
 		RendererContextMtl()
 			: m_metalLayer(NULL)
 			, m_backBufferPixelFormatHash(0)
+			, m_capture(NULL)
+			, m_captureSize(0)
 			, m_maxAnisotropy(1)
 			, m_bufferIndex(0)
 			, m_numWindows(1)
@@ -475,11 +483,11 @@ namespace bgfx { namespace mtl
 								 | BGFX_CAPS_INSTANCING
 							     | BGFX_CAPS_FRAGMENT_DEPTH
 								 | BGFX_CAPS_BLEND_INDEPENDENT
-								 | BGFX_CAPS_COMPUTE	// TODO: api/hw supports it but metal compute shaders are not yet supported
+							   //| BGFX_CAPS_COMPUTE	// TODO: api/hw supports it but metal compute shaders are not yet supported
 								 | BGFX_CAPS_INDEX32
 							   //| BGFX_CAPS_DRAW_INDIRECT // TODO: support on iOS9+gpu family3+ and on macOS
 							     | BGFX_CAPS_TEXTURE_BLIT
-							   //| BGFX_CAPS_TEXTURE_READ_BACK //TODO: is this supported???
+							     | BGFX_CAPS_TEXTURE_READ_BACK
 							     | BGFX_CAPS_OCCLUSION_QUERY
 							     | BGFX_CAPS_ALPHA_TO_COVERAGE
 								 );
@@ -635,6 +643,8 @@ namespace bgfx { namespace mtl
 			{
 				m_textures[ii].destroy();
 			}
+			
+			captureFinish();
 
 			MTL_RELEASE(m_depthStencilDescriptor);
 			MTL_RELEASE(m_frontFaceStencilDescriptor);
@@ -768,8 +778,24 @@ namespace bgfx { namespace mtl
 		{
 		}
 
-		void readTexture(TextureHandle /*_handle*/, void* /*_data*/) BX_OVERRIDE
+		void readTexture(TextureHandle _handle, void* _data) BX_OVERRIDE
 		{
+			m_commandBuffer.commit();
+			m_commandBuffer.waitUntilCompleted();
+			MTL_RELEASE(m_commandBuffer)
+			
+			const TextureMtl& texture = m_textures[_handle.idx];
+			
+			uint32_t width  = texture.m_ptr.width();
+			uint32_t height = texture.m_ptr.height();
+			const uint8_t bpp = getBitsPerPixel(TextureFormat::Enum(texture.m_textureFormat) );
+
+			MTLRegion region = { { 0, 0, 0 }, { width, height, 1 } };
+			
+			texture.m_ptr.getBytes(_data, width*bpp/8, 0, region, 0, 0);
+			
+			m_commandBuffer = m_commandQueue.commandBuffer();
+			retain(m_commandBuffer); //NOTE: keep alive to be useable at 'flip'
 		}
 
 		void resizeTexture(TextureHandle _handle, uint16_t _width, uint16_t _height, uint8_t _numMips) BX_OVERRIDE
@@ -863,6 +889,13 @@ namespace bgfx { namespace mtl
 			m_uniforms[_handle.idx] = NULL;
 		}
 
+		//cmdPre
+		void saveScreenShotPre(const char* _filePath) BX_OVERRIDE
+		{
+			m_saveScreenshot = true;
+		}
+
+		//cmdPost
 		void saveScreenShot(const char* _filePath) BX_OVERRIDE
 		{
 			if (NULL == m_screenshotTarget)
@@ -1152,6 +1185,8 @@ namespace bgfx { namespace mtl
 				{
 					m_frameBuffers[ii].postReset();
 				}
+				
+				updateCapture();
 
 				m_textVideoMem.resize(false, _resolution.m_width, _resolution.m_height);
 				m_textVideoMem.clear();
@@ -1168,6 +1203,90 @@ namespace bgfx { namespace mtl
 			}
 		}
 
+
+		void updateCapture()
+		{
+			if (m_resolution.m_flags&BGFX_RESET_CAPTURE)
+			{
+				m_captureSize = m_resolution.m_width*m_resolution.m_height*4;
+				m_capture = BX_REALLOC(g_allocator, m_capture, m_captureSize);
+				g_callback->captureBegin(m_resolution.m_width, m_resolution.m_height, m_resolution.m_width*4, TextureFormat::BGRA8, false);
+			}
+			else
+			{
+				captureFinish();
+			}
+		}
+
+		void capture()
+		{
+			if (NULL != m_capture)
+			{
+				if (NULL == m_screenshotTarget)
+					return;
+				
+				m_renderCommandEncoder.endEncoding();
+				
+				m_commandBuffer.commit();
+				m_commandBuffer.waitUntilCompleted();
+				MTL_RELEASE(m_commandBuffer)
+				
+				MTLRegion region = { { 0, 0, 0 }, { m_resolution.m_width, m_resolution.m_height, 1 } };
+				
+				//TODO: enable screenshot target when capturing
+				m_screenshotTarget.getBytes(m_capture, 4*m_resolution.m_width, 0, region, 0, 0);
+				
+				m_commandBuffer = m_commandQueue.commandBuffer();
+				retain(m_commandBuffer); //NOTE: keep alive to be useable at 'flip'
+				
+				if (m_screenshotTarget.pixelFormat() == MTLPixelFormatRGBA8Uint)
+				{
+					imageSwizzleBgra8(m_resolution.m_width, m_resolution.m_height, m_resolution.m_width*4, m_capture, m_capture);
+				}
+		
+				g_callback->captureFrame(m_capture, m_captureSize);
+				
+				RenderPassDescriptor renderPassDescriptor = newRenderPassDescriptor();
+				setFrameBuffer(renderPassDescriptor, m_renderCommandEncoderFrameBufferHandle);
+				
+				for(uint32_t ii = 0; ii < g_caps.maxFBAttachments; ++ii)
+				{
+					MTLRenderPassColorAttachmentDescriptor* desc = renderPassDescriptor.colorAttachments[ii];
+					if ( desc.texture != NULL)
+						desc.loadAction = MTLLoadActionLoad;
+				}
+				
+				RenderPassDepthAttachmentDescriptor depthAttachment = renderPassDescriptor.depthAttachment;
+				if (NULL != depthAttachment.texture)
+				{
+					depthAttachment.loadAction = MTLLoadActionLoad;
+					depthAttachment.storeAction = MTLStoreActionStore;
+				}
+				
+				RenderPassStencilAttachmentDescriptor stencilAttachment = renderPassDescriptor.stencilAttachment;
+				if (NULL != stencilAttachment.texture)
+				{
+					stencilAttachment.loadAction   = MTLLoadActionLoad;
+					stencilAttachment.storeAction  = MTLStoreActionStore;
+				}
+			
+				m_renderCommandEncoder = m_commandBuffer.renderCommandEncoderWithDescriptor(renderPassDescriptor);
+				MTL_RELEASE(renderPassDescriptor);
+			}
+		}
+
+		void captureFinish()
+		{
+			if (NULL != m_capture)
+			{
+				g_callback->captureEnd();
+				BX_FREE(g_allocator, m_capture);
+				m_capture = NULL;
+				m_captureSize = 0;
+			}
+		}
+
+
 		void setShaderUniform(uint8_t _flags, uint32_t _loc, const void* _val, uint32_t _numRegs)
 		{
 			uint32_t offset = 0 != (_flags&BGFX_UNIFORM_FRAGMENTBIT)
@@ -1424,17 +1543,26 @@ namespace bgfx { namespace mtl
 				for (uint32_t ii = 0; ii < frameBuffer.m_num; ++ii)
 				{
 					const TextureMtl& texture = m_textures[frameBuffer.m_colorHandle[ii].idx];
-					renderPassDescriptor.colorAttachments[ii].texture = texture.m_ptr;
+					renderPassDescriptor.colorAttachments[ii].texture = texture.m_ptrMSAA ? texture.m_ptrMSAA : texture.m_ptr;
+					renderPassDescriptor.colorAttachments[ii].resolveTexture = texture.m_ptrMSAA ? texture.m_ptr.m_obj : NULL;
 				}
 
 				if (isValid(frameBuffer.m_depthHandle) )
 				{
 					const TextureMtl& texture = m_textures[frameBuffer.m_depthHandle.idx];
-					renderPassDescriptor.depthAttachment.texture = texture.m_ptr;
+					renderPassDescriptor.depthAttachment.texture = texture.m_ptrMSAA ? texture.m_ptrMSAA : texture.m_ptr;
 					renderPassDescriptor.stencilAttachment.texture = texture.m_ptrStencil;
 
-					if ( texture.m_textureFormat == TextureFormat::D24S8)
-						renderPassDescriptor.stencilAttachment.texture = texture.m_ptr;
+					if ( texture.m_textureFormat == TextureFormat::D24S8)//TODO: msaa and stencil iOS8 hack
+					{
+						if ( texture.m_ptr.pixelFormat() == 255 /* Depth24Unorm_Stencil8 */||
+							 texture.m_ptr.pixelFormat() == 260 /* Depth32Float_Stencil8 */ )
+						{
+							renderPassDescriptor.stencilAttachment.texture = renderPassDescriptor.depthAttachment.texture;
+						}
+						else
+							renderPassDescriptor.stencilAttachment.texture = texture.m_ptrMSAA ? texture.m_ptrMSAA : texture.m_ptrStencil;
+					}
 				}
 			}
 
@@ -1643,6 +1771,8 @@ namespace bgfx { namespace mtl
 		bool m_rtMsaa;
 
 		Resolution m_resolution;
+		void* m_capture;
+		uint32_t m_captureSize;
 
 		// descriptors
 		RenderPipelineDescriptor m_renderPipelineDescriptor;
@@ -1916,6 +2046,7 @@ namespace bgfx { namespace mtl
 				for (uint32_t ii = 0; ii < frameBuffer.m_num; ++ii)
 				{
 					const TextureMtl& texture = s_renderMtl->m_textures[frameBuffer.m_colorHandle[ii].idx];
+					pd.sampleCount = NULL != texture.m_ptrMSAA ? texture.m_ptrMSAA.sampleCount() : 1;
 					pd.colorAttachments[ii].pixelFormat = texture.m_ptr.m_obj.pixelFormat;
 				}
 
@@ -1927,13 +2058,14 @@ namespace bgfx { namespace mtl
 					{
 						pd.stencilAttachmentPixelFormat = texture.m_ptrStencil.m_obj.pixelFormat;
 					}
-
-//					if ( texture.m_textureFormat == TextureFormat::D24S8)
-//						pd.stencilAttachmentPixelFormat = texture.m_ptr.m_obj.pixelFormat;
+					else
+					{
+						if ( texture.m_textureFormat == TextureFormat::D24S8)
+							pd.stencilAttachmentPixelFormat = texture.m_ptr.m_obj.pixelFormat;
+					}
 				}
 			}
 
-			// TODO: BGFX_STATE_MSAA using _fbHandle texture msaa values
 			const uint32_t blend    = uint32_t( (_state&BGFX_STATE_BLEND_MASK)>>BGFX_STATE_BLEND_SHIFT);
 			const uint32_t equation = uint32_t( (_state&BGFX_STATE_BLEND_EQUATION_MASK)>>BGFX_STATE_BLEND_EQUATION_SHIFT);
 
@@ -2273,8 +2405,8 @@ namespace bgfx { namespace mtl
 			const bool computeWrite = 0 != (_flags&BGFX_TEXTURE_COMPUTE_WRITE);
 			const bool renderTarget = 0 != (_flags&BGFX_TEXTURE_RT_MASK);
 			const bool srgb			= 0 != (_flags&BGFX_TEXTURE_SRGB) || imageContainer.m_srgb;
-//			const uint32_t msaaQuality = bx::uint32_satsub( (_flags&BGFX_TEXTURE_RT_MSAA_MASK)>>BGFX_TEXTURE_RT_MSAA_SHIFT, 1);
-//			const DXGI_SAMPLE_DESC& msaa = s_msaa[msaaQuality];
+			const uint32_t msaaQuality = bx::uint32_satsub( (_flags&BGFX_TEXTURE_RT_MSAA_MASK)>>BGFX_TEXTURE_RT_MSAA_SHIFT, 1);
+			int sampleCount = s_msaa[msaaQuality];
 
 			MTLPixelFormat format = MTLPixelFormatInvalid;
 			if (srgb)
@@ -2297,7 +2429,7 @@ namespace bgfx { namespace mtl
 			desc.height = textureHeight;
 			desc.depth  = bx::uint32_max(1,imageContainer.m_depth);
 			desc.mipmapLevelCount = imageContainer.m_numMips;
-			desc.sampleCount      = 1; //TODO: set samplecount -  If textureType is not MTLTextureType2DMultisample, the value must be 1.
+			desc.sampleCount      = 1;
 
 			if (s_renderMtl->m_iOS9Runtime || s_renderMtl->m_macOS11Runtime)
 			{
@@ -2316,6 +2448,16 @@ namespace bgfx { namespace mtl
 			}
 
 			m_ptr = s_renderMtl->m_device.newTextureWithDescriptor(desc);
+			
+			if ( sampleCount > 1)
+			{
+				desc.textureType = MTLTextureType2DMultisample;
+				desc.sampleCount = sampleCount;
+				if (s_renderMtl->m_iOS9Runtime || s_renderMtl->m_macOS11Runtime)
+					desc.storageMode = (MTLStorageMode)( 2 /*MTLStorageModePrivate*/);
+				m_ptrMSAA = s_renderMtl->m_device.newTextureWithDescriptor(desc);
+			}
+			
 			if (m_requestedFormat == TextureFormat::D24S8
 			&&  desc.pixelFormat  == MTLPixelFormatDepth32Float)
 			{
@@ -2490,9 +2632,17 @@ namespace bgfx { namespace mtl
 			const TextureMtl& texture = s_renderMtl->m_textures[m_colorHandle[ii].idx];
 			murmur.add((uint32_t)texture.m_ptr.pixelFormat());
 		}
-		const TextureMtl& depthTexture = s_renderMtl->m_textures[m_depthHandle.idx];
-		murmur.add((uint32_t)depthTexture.m_ptr.pixelFormat());
-		murmur.add((uint32_t)(NULL != depthTexture.m_ptrStencil ? depthTexture.m_ptrStencil.pixelFormat() : MTLPixelFormatInvalid));
+		if (!isValid(m_depthHandle))
+		{
+			murmur.add((uint32_t)MTLPixelFormatInvalid);
+			murmur.add((uint32_t)MTLPixelFormatInvalid);
+		}
+		else
+		{
+			const TextureMtl& depthTexture = s_renderMtl->m_textures[m_depthHandle.idx];
+			murmur.add((uint32_t)depthTexture.m_ptr.pixelFormat());
+			murmur.add((uint32_t)(NULL != depthTexture.m_ptrStencil ? depthTexture.m_ptrStencil.pixelFormat() : MTLPixelFormatInvalid));
+		}
 		murmur.add(1); //SampleCount
 
 		m_pixelFormatHash = murmur.end();
@@ -2804,6 +2954,7 @@ namespace bgfx { namespace mtl
 						if (0 != m_renderCommandEncoder)
 						{
 							m_renderCommandEncoder.endEncoding();
+							m_renderCommandEncoder = 0;
 						}
 						m_blitCommandEncoder = getBlitCommandEncoder();
 
@@ -2858,6 +3009,11 @@ namespace bgfx { namespace mtl
 
 					if ( NULL == m_renderCommandEncoder || fbh.idx != _render->m_fb[view].idx )
 					{
+						if (0 != m_renderCommandEncoder)
+						{
+							m_renderCommandEncoder.endEncoding();
+						}
+						
 						RenderPassDescriptor renderPassDescriptor = newRenderPassDescriptor();
 						renderPassDescriptor.visibilityResultBuffer = m_occlusionQuery.m_buffer;
 
@@ -2899,7 +3055,7 @@ namespace bgfx { namespace mtl
 									{
 										desc.loadAction = MTLLoadActionLoad;
 									}
-									desc.storeAction = NULL != m_backBufferColorMSAA ? MTLStoreActionMultisampleResolve : MTLStoreActionStore;
+									desc.storeAction = desc.texture.sampleCount > 1 ? MTLStoreActionMultisampleResolve : MTLStoreActionStore;
 								}
 							}
 
@@ -2946,17 +3102,11 @@ namespace bgfx { namespace mtl
 							RenderPassStencilAttachmentDescriptor stencilAttachment = renderPassDescriptor.stencilAttachment;
 							if (NULL != stencilAttachment.texture)
 							{
-								stencilAttachment.clearStencil = clr.m_stencil;
 								stencilAttachment.loadAction   = MTLLoadActionLoad;
 								stencilAttachment.storeAction  = MTLStoreActionStore;
 							}
 						}
 
-						if (0 != m_renderCommandEncoder)
-						{
-							m_renderCommandEncoder.endEncoding();
-						}
-
 						rce = m_commandBuffer.renderCommandEncoderWithDescriptor(renderPassDescriptor);
 						m_renderCommandEncoder = rce;
 						m_renderCommandEncoderFrameBufferHandle = fbh;
@@ -3355,7 +3505,8 @@ namespace bgfx { namespace mtl
 			if (0 < _render->m_num)
 			{
 				captureElapsed = -bx::getHPCounter();
-				//capture();
+				capture();
+				rce = m_renderCommandEncoder; //TODO: ugly, can create new encoder
 				captureElapsed += bx::getHPCounter();
 			}
 		}