diff options
Diffstat (limited to 'Runtime/GfxDevice/threaded')
18 files changed, 9290 insertions, 0 deletions
diff --git a/Runtime/GfxDevice/threaded/ClientIDMapper.h b/Runtime/GfxDevice/threaded/ClientIDMapper.h new file mode 100644 index 0000000..4156701 --- /dev/null +++ b/Runtime/GfxDevice/threaded/ClientIDMapper.h @@ -0,0 +1,46 @@ +#ifndef CLIENTIDMAPPER_H +#define CLIENTIDMAPPER_H + +#include "Runtime/Utilities/dynamic_array.h" +#include "Runtime/GfxDevice/GfxDevice.h" + +#if ENABLE_GFXDEVICE_REMOTE_PROCESS +#define ClientIDWrapper(type) ClientIDMapper::ClientID +#define ClientIDWrapperHandle(type) ClientIDMapper::ClientID +#else +#define ClientIDWrapper(type) type* +#define ClientIDWrapperHandle(type) type +#endif + +class ClientIDMapper { +public: + typedef UInt32 ClientID; + + ClientIDMapper() : + m_HighestAllocatedID(0) + { + } + + ClientID CreateID() + { + if (m_FreeIDs.empty()) + return ++m_HighestAllocatedID; + else + { + ClientID retval = m_FreeIDs.back(); + m_FreeIDs.pop_back(); + return retval; + } + } + + void FreeID(ClientID cid) + { + m_FreeIDs.push_back(cid); + } + +private: + ClientID m_HighestAllocatedID; + dynamic_array<ClientID> m_FreeIDs; +}; + +#endif
\ No newline at end of file diff --git a/Runtime/GfxDevice/threaded/GfxCommands.h b/Runtime/GfxDevice/threaded/GfxCommands.h new file mode 100644 index 0000000..e148431 --- /dev/null +++ b/Runtime/GfxDevice/threaded/GfxCommands.h @@ -0,0 +1,669 @@ +#pragma once + +#include "Runtime/GfxDevice/GfxDevice.h" +#include "Runtime/GfxDevice/ChannelAssigns.h" +#include "Runtime/GfxDevice/threaded/ThreadedDeviceStates.h" +#include "Runtime/GfxDevice/threaded/ClientIDMapper.h" + +struct ClientDeviceVBO; + + +enum GfxCommand +{ + kGfxCmd_Unused = 10000, + kGfxCmd_InvalidateState, + kGfxCmd_VerifyState, + kGfxCmd_SetMaxBufferedFrames, + kGfxCmd_Clear, + kGfxCmd_SetUserBackfaceMode, + kGfxCmd_SetInvertProjectionMatrix, + kGfxCmd_SetViewportOffset, + kGfxCmd_CreateBlendState, + kGfxCmd_CreateDepthState, + kGfxCmd_CreateStencilState, + kGfxCmd_CreateRasterState, + kGfxCmd_SetBlendState, + kGfxCmd_SetDepthState, + kGfxCmd_SetStencilState, + kGfxCmd_SetRasterState, + kGfxCmd_SetSRGBState, + kGfxCmd_SetWorldMatrix, + kGfxCmd_SetViewMatrix, + kGfxCmd_SetProjectionMatrix, + kGfxCmd_SetInverseScale, + kGfxCmd_SetNormalizationBackface, + kGfxCmd_SetFFLighting, + kGfxCmd_SetMaterial, + kGfxCmd_SetColor, + kGfxCmd_SetViewport, + kGfxCmd_SetScissorRect, + kGfxCmd_DisableScissor, + kGfxCmd_CreateTextureCombiners, + kGfxCmd_DeleteTextureCombiners, + kGfxCmd_SetTextureCombiners, + kGfxCmd_SetTexture, + kGfxCmd_SetTextureParams, + kGfxCmd_SetTextureTransform, + kGfxCmd_SetTextureName, + kGfxCmd_SetMaterialProperties, + kGfxCmd_CreateGpuProgram, + kGfxCmd_SetShaders, + kGfxCmd_CreateShaderParameters, + kGfxCmd_DestroySubProgram, + kGfxCmd_SetConstantBufferInfo, + kGfxCmd_DisableLights, + kGfxCmd_SetLight, + kGfxCmd_SetAmbient, + kGfxCmd_EnableFog, + kGfxCmd_DisableFog, + kGfxCmd_BeginSkinning, + kGfxCmd_SkinMesh, + kGfxCmd_EndSkinning, + kGfxCmd_BeginStaticBatching, + kGfxCmd_StaticBatchMesh, + kGfxCmd_EndStaticBatching, + kGfxCmd_BeginDynamicBatching, + kGfxCmd_DynamicBatchMesh, +#if ENABLE_SPRITES + kGfxCmd_DynamicBatchSprite, +#endif + kGfxCmd_EndDynamicBatching, + kGfxCmd_AddBatchingStats, + kGfxCmd_CreateRenderColorSurface, + kGfxCmd_CreateRenderDepthSurface, + kGfxCmd_DestroyRenderSurface, + kGfxCmd_DiscardContents, + kGfxCmd_SetRenderTarget, + kGfxCmd_SetRenderTargetWithFlags, + kGfxCmd_ResolveColorSurface, + kGfxCmd_ResolveDepthIntoTexture, + kGfxCmd_SetSurfaceFlags, + kGfxCmd_UploadTexture2D, + kGfxCmd_UploadTextureSubData2D, + kGfxCmd_UploadTextureCube, + kGfxCmd_UploadTexture3D, + kGfxCmd_DeleteTexture, + kGfxCmd_BeginFrame, + kGfxCmd_EndFrame, + kGfxCmd_PresentFrame, + kGfxCmd_HandleInvalidState, + kGfxCmd_FinishRendering, + kGfxCmd_InsertCPUFence, + kGfxCmd_ImmediateVertex, + kGfxCmd_ImmediateNormal, + kGfxCmd_ImmediateColor, + kGfxCmd_ImmediateTexCoordAll, + kGfxCmd_ImmediateTexCoord, + kGfxCmd_ImmediateBegin, + kGfxCmd_ImmediateEnd, + kGfxCmd_CaptureScreenshot, + kGfxCmd_ReadbackImage, + kGfxCmd_GrabIntoRenderTexture, + kGfxCmd_SetActiveContext, + kGfxCmd_ResetFrameStats, + kGfxCmd_BeginFrameStats, + kGfxCmd_EndFrameStats, + kGfxCmd_SaveDrawStats, + kGfxCmd_RestoreDrawStats, + kGfxCmd_SynchronizeStats, + kGfxCmd_SetAntiAliasFlag, + kGfxCmd_SetWireframe, + kGfxCmd_DrawUserPrimitives, + kGfxCmd_Quit, + + kGfxCmd_VBO_UpdateVertexData, + kGfxCmd_VBO_UpdateIndexData, + kGfxCmd_VBO_Draw, + kGfxCmd_VBO_DrawCustomIndexed, + kGfxCmd_VBO_Recreate, + kGfxCmd_VBO_MapVertexStream, + kGfxCmd_VBO_IsVertexBufferLost, + kGfxCmd_VBO_SetVertexStreamMode, + kGfxCmd_VBO_SetIndicesDynamic, + kGfxCmd_VBO_GetRuntimeMemorySize, + kGfxCmd_VBO_GetVertexSize, + kGfxCmd_VBO_AddExtraUvChannels, + kGfxCmd_VBO_CopyExtraUvChannels, + kGfxCmd_VBO_Constructor, + kGfxCmd_VBO_Destructor, + kGfxCmd_VBO_UseAsStreamOutput, + + kGfxCmd_DynVBO_Chunk, + kGfxCmd_DynVBO_DrawChunk, + + kGfxCmd_DisplayList_Call, + kGfxCmd_DisplayList_End, + + kGfxCmd_CreateWindow, + kGfxCmd_SetActiveWindow, + kGfxCmd_WindowReshape, + kGfxCmd_WindowDestroy, + kGfxCmd_BeginRendering, + kGfxCmd_EndRendering, + + kGfxCmd_AcquireThreadOwnership, + kGfxCmd_ReleaseThreadOwnership, + + kGfxCmd_BeginProfileEvent, + kGfxCmd_EndProfileEvent, + kGfxCmd_ProfileControl, + kGfxCmd_BeginTimerQueries, + kGfxCmd_EndTimerQueries, + + kGfxCmd_TimerQuery_Constructor, + kGfxCmd_TimerQuery_Destructor, + kGfxCmd_TimerQuery_Measure, + kGfxCmd_TimerQuery_GetElapsed, + + kGfxCmd_InsertCustomMarker, + + kGfxCmd_SetComputeBufferData, + kGfxCmd_GetComputeBufferData, + kGfxCmd_CopyComputeBufferCount, + kGfxCmd_SetRandomWriteTargetTexture, + kGfxCmd_SetRandomWriteTargetBuffer, + kGfxCmd_ClearRandomWriteTargets, + kGfxCmd_CreateComputeProgram, + kGfxCmd_DestroyComputeProgram, + kGfxCmd_CreateComputeConstantBuffers, + kGfxCmd_DestroyComputeConstantBuffers, + kGfxCmd_CreateComputeBuffer, + kGfxCmd_DestroyComputeBuffer, + kGfxCmd_UpdateComputeConstantBuffers, + kGfxCmd_UpdateComputeResources, + kGfxCmd_DispatchComputeProgram, + kGfxCmd_DrawNullGeometry, + kGfxCmd_DrawNullGeometryIndirect, + kGfxCmd_QueryGraphicsCaps, + kGfxCmd_SetGpuProgramParameters, + kGfxCmd_DeleteGPUSkinningInfo, + kGfxCmd_SkinOnGPU, + kGfxCmd_UpdateSkinSourceData, + kGfxCmd_UpdateSkinBonePoses, + + // Keep platform specific flags last +#if UNITY_XENON + kGfxCmd_RawVBO_Constructor, + kGfxCmd_RawVBO_Destructor, + kGfxCmd_RawVBO_Next, + kGfxCmd_RawVBO_Write, + kGfxCmd_RawVBO_InvalidateGpuCache, + + kGfxCmd_EnablePersistDisplayOnQuit, + kGfxCmd_OnLastFrameCallback, + + kGfxCmd_RegisterTexture2D, + kGfxCmd_PatchTexture2D, + kGfxCmd_DeleteTextureEntryOnly, + kGfxCmd_UnbindAndDelayReleaseTexture, + kGfxCmd_SetTextureWrapModes, + + kGfxCmd_VideoPlayer_Constructor, + kGfxCmd_VideoPlayer_Destructor, + kGfxCmd_VideoPlayer_Render, + kGfxCmd_VideoPlayer_Pause, + kGfxCmd_VideoPlayer_Resume, + kGfxCmd_VideoPlayer_Stop, + kGfxCmd_VideoPlayer_SetPlaySpeed, + kGfxCmd_VideoPlayer_Play, + kGfxCmd_SetHiStencilState, + kGfxCmd_HiStencilFlush, + kGfxCmd_SetNullPixelShader, + kGfxCmd_EnableHiZ, +#endif + + kGfxCmd_Count +}; + +typedef int GfxCmdBool; + + +struct GfxCmdClear +{ + UInt32 clearFlags; + Vector4f color; + float depth; + int stencil; +}; + +struct GfxCmdSetNormalizationBackface +{ + NormalizationMode mode; + bool backface; +}; + +struct GfxCmdSetFFLighting +{ + bool on; + bool separateSpecular; + ColorMaterialMode colorMaterial; +}; + +struct GfxCmdCreateTextureCombiners +{ + int count; + bool hasVertexColorOrLighting; + bool usesAddSpecular; +}; + +struct GfxCmdSetTexture +{ + ShaderType shaderType; + int unit; + int samplerUnit; + TextureID texture; + TextureDimension dim; + float bias; +}; + +struct GfxCmdSetTextureParams +{ + TextureID texture; + TextureDimension texDim; + TextureFilterMode filter; + TextureWrapMode wrap; + int anisoLevel; + bool hasMipMap; + TextureColorSpace colorSpace; +}; + +struct GfxCmdSetTextureName +{ + TextureID texture; + int nameLength; +}; + +struct GfxCmdSetTextureBias +{ + int unit; + float bias; +}; + +struct GfxCmdSetTextureTransform +{ + int unit; + TextureDimension dim; + TexGenMode texGen; + bool identity; + Matrix4x4f matrix; +}; + +struct GfxCmdSetMaterialProperties +{ + int propertyCount; + int bufferSize; +}; + +#if !ENABLE_GFXDEVICE_REMOTE_PROCESS +struct GfxCmdCreateGpuProgram +{ + const char *source; + CreateGpuProgramOutput* output; + GpuProgram** result; +}; +#endif + +struct GfxCmdSetShaders +{ + ClientIDWrapper(GpuProgram) programs[kShaderTypeCount]; + ClientIDWrapper(const GpuProgramParameters) params[kShaderTypeCount]; + int paramsBufferSize[kShaderTypeCount]; +}; + +struct GfxCmdCreateShaderParameters +{ + ShaderLab::SubProgram* program; + FogMode fogMode; +}; + +struct GfxCmdBeginStaticBatching +{ + ChannelAssigns channels; + GfxPrimitiveType topology; +}; + +struct GfxCmdStaticBatchMesh +{ + UInt32 firstVertex; + UInt32 vertexCount; + IndexBufferData indices; + UInt32 firstIndexByte; + UInt32 indexCount; +}; + +struct GfxCmdEndStaticBatching +{ + ClientDeviceVBO* vbo; + Matrix4x4f matrix; + TransformType transformType; + int sourceChannels; +}; + +struct GfxCmdBeginDynamicBatching +{ + ChannelAssigns shaderChannels; + UInt32 channelsInVBO; + size_t maxVertices; + size_t maxIndices; + GfxPrimitiveType topology; +}; + +struct GfxCmdDynamicBatchMesh +{ + Matrix4x4f matrix; + VertexBufferData vertices; + UInt32 firstVertex; + UInt32 vertexCount; + IndexBufferData indices; + UInt32 firstIndexByte; + UInt32 indexCount; +}; + +#if ENABLE_SPRITES +struct GfxCmdDynamicBatchSprite +{ + Matrix4x4f matrix; + const SpriteRenderData *sprite; + ColorRGBA32 color; +}; +#endif +struct GfxCmdEndDynamicBatching +{ + TransformType transformType; +}; + +struct GfxCmdAddBatchingStats +{ + int batchedTris; + int batchedVerts; + int batchedCalls; +}; + +struct GfxCmdCreateRenderColorSurface +{ + TextureID textureID; + int width; + int height; + int samples; + int depth; + TextureDimension dim; + RenderTextureFormat format; + UInt32 createFlags; +}; + +struct GfxCmdCreateRenderDepthSurface +{ + TextureID textureID; + int width; + int height; + int samples; + TextureDimension dim; + DepthBufferFormat depthFormat; + UInt32 createFlags; +}; + +struct GfxCmdSetRenderTarget +{ + ClientIDWrapperHandle(RenderSurfaceHandle) colorHandles[kMaxSupportedRenderTargets]; + ClientIDWrapperHandle(RenderSurfaceHandle) depthHandle; + int colorCount; + int mipLevel; + CubemapFace face; +}; + +struct GfxCmdResolveDepthIntoTexture +{ + ClientIDWrapperHandle(RenderSurfaceHandle) colorHandle; + ClientIDWrapperHandle(RenderSurfaceHandle) depthHandle; +}; + +struct GfxCmdSetSurfaceFlags +{ + ClientIDWrapperHandle(RenderSurfaceHandle) surf; + UInt32 flags; + UInt32 keepFlags; +}; + +struct GfxCmdUploadTexture2D +{ + TextureID texture; + TextureDimension dimension; + int srcSize; + int width; + int height; + TextureFormat format; + int mipCount; + UInt32 uploadFlags; + int skipMipLevels; + TextureUsageMode usageMode; + TextureColorSpace colorSpace; +}; + +struct GfxCmdUploadTextureSubData2D +{ + TextureID texture; + int srcSize; + int mipLevel; + int x; + int y; + int width; + int height; + TextureFormat format; + TextureColorSpace colorSpace; +}; + +struct GfxCmdUploadTextureCube +{ + TextureID texture; + int srcSize; + int faceDataSize; + int size; + TextureFormat format; + int mipCount; + UInt32 uploadFlags; + TextureColorSpace colorSpace; +}; + +struct GfxCmdUploadTexture3D +{ + TextureID texture; + int srcSize; + int width; + int height; + int depth; + TextureFormat format; + int mipCount; + UInt32 uploadFlags; +}; + +struct GfxCmdDrawUserPrimitives +{ + GfxPrimitiveType type; + int vertexCount; + UInt32 vertexChannels; + int stride; +}; + +struct GfxCmdVBODraw +{ +#if ENABLE_GFXDEVICE_REMOTE_PROCESS + ClientDeviceVBO vbo; +#else + ClientDeviceVBO* vbo; +#endif + ChannelAssigns channels; + UInt32 firstIndexByte; + UInt32 indexCount; + GfxPrimitiveType topology; + UInt32 firstVertex; + UInt32 vertexCount; +}; + +struct GfxCmdVBODrawCustomIndexed +{ +#if ENABLE_GFXDEVICE_REMOTE_PROCESS + ClientDeviceVBO vbo; +#else + ClientDeviceVBO* vbo; +#endif + ChannelAssigns channels; + UInt32 indexCount; + GfxPrimitiveType topology; + UInt32 vertexRangeBegin; + UInt32 vertexRangeEnd; + UInt32 drawVertexCount; +}; + +struct GfxCmdVBODrawStripWireframe +{ +#if ENABLE_GFXDEVICE_REMOTE_PROCESS + ClientDeviceVBO vbo; +#else + ClientDeviceVBO* vbo; +#endif + ChannelAssigns channels; + UInt32 indexCount; + UInt32 triCount; + UInt32 vertexCount; +}; + +struct GfxCmdVBOMapVertexStream +{ +#if ENABLE_GFXDEVICE_REMOTE_PROCESS + ClientDeviceVBO vbo; +#else + ClientDeviceVBO* vbo; +#endif + unsigned stream; + UInt32 size; +}; + +struct GfxCmdVBOSetVertexStreamMode +{ +#if ENABLE_GFXDEVICE_REMOTE_PROCESS + ClientDeviceVBO vbo; +#else + ClientDeviceVBO* vbo; +#endif + unsigned stream; + int mode; +}; + +struct GfxCmdVBOSetSetIndicesDynamic +{ +#if ENABLE_GFXDEVICE_REMOTE_PROCESS + ClientDeviceVBO vbo; +#else + ClientDeviceVBO* vbo; +#endif + int dynamic; +}; + +struct GfxCmdVBOAddExtraUvChannels +{ +#if ENABLE_GFXDEVICE_REMOTE_PROCESS + ClientDeviceVBO vbo; +#else + ClientDeviceVBO* vbo; +#endif + UInt32 size; + int extraUvCount; +}; + +struct GfxCmdVBOCopyExtraUvChannels +{ +#if ENABLE_GFXDEVICE_REMOTE_PROCESS + ClientDeviceVBO dest; + ClientDeviceVBO source; +#else + ClientDeviceVBO* dest; + ClientDeviceVBO* source; +#endif + +}; + + +struct GfxCmdVector3 +{ + float x; + float y; + float z; +}; + +struct GfxCmdVector4 +{ + float x; + float y; + float z; + float w; +}; + +struct GfxCmdImmediateTexCoord +{ + int unit; + float x; + float y; + float z; +}; + +struct GfxCmdCaptureScreenshot +{ + int left; + int bottom; + int width; + int height; + UInt8* rgba32; + bool* success; +}; + +struct GfxCmdReadbackImage +{ + ImageReference& image; + int left; + int bottom; + int width; + int height; + int destX; + int destY; + bool* success; +}; + +struct GfxCmdGrabIntoRenderTexture +{ + ClientIDWrapperHandle(RenderSurfaceHandle) rs; + ClientIDWrapperHandle(RenderSurfaceHandle) rd; + int x; + int y; + int width; + int height; +}; + +struct GfxCmdDynVboChunk +{ + UInt32 channelMask; + UInt32 vertexStride; + UInt32 actualVertices; + UInt32 actualIndices; + UInt32 renderMode; +}; + +#if UNITY_WIN && UNITY_EDITOR + +struct GfxCmdWindowReshape +{ + int width; + int height; + DepthBufferFormat depthFormat; + int antiAlias; +}; + +struct GfxCmdCreateWindow +{ + HWND window; + int width; + int height; + DepthBufferFormat depthFormat; + int antiAlias; +}; + +#endif diff --git a/Runtime/GfxDevice/threaded/GfxDeviceClient.cpp b/Runtime/GfxDevice/threaded/GfxDeviceClient.cpp new file mode 100644 index 0000000..39295c6 --- /dev/null +++ b/Runtime/GfxDevice/threaded/GfxDeviceClient.cpp @@ -0,0 +1,3922 @@ +#include "UnityPrefix.h" + +#if ENABLE_MULTITHREADED_CODE +#if ENABLE_SPRITES +#include "Runtime/Graphics/SpriteFrame.h" +#endif +#include "Runtime/GfxDevice/threaded/GfxDeviceClient.h" +#include "Runtime/GfxDevice/threaded/GfxDeviceWorker.h" +#include "Runtime/GfxDevice/threaded/GfxCommands.h" +#include "Runtime/GfxDevice/threaded/GfxReturnStructs.h" +#include "Runtime/GfxDevice/GfxDeviceSetup.h" +#include "Runtime/Threads/Thread.h" +#include "Runtime/Threads/ThreadUtility.h" +#include "Runtime/GfxDevice/threaded/ThreadedVBO.h" +#include "Runtime/Shaders/MaterialProperties.h" +#include "Runtime/GfxDevice/threaded/ThreadedWindow.h" +#include "Runtime/GfxDevice/threaded/ThreadedDisplayList.h" +#include "Runtime/GfxDevice/threaded/ThreadedTimerQuery.h" +#include "External/shaderlab/Library/program.h" +#include "External/shaderlab/Library/properties.h" +#include "External/shaderlab/Library/TextureBinding.h" +#include "External/shaderlab/Library/shaderlab.h" +#include "External/shaderlab/Library/texenv.h" +#include "External/shaderlab/Library/pass.h" +#include "Runtime/Filters/Mesh/MeshSkinning.h" +#include "Runtime/Graphics/GraphicsHelper.h" +#include "Runtime/Profiler/Profiler.h" +#include "Runtime/GfxDevice/GPUSkinningInfo.h" +#include "Runtime/Profiler/ProfilerImpl.h" +#if UNITY_XENON +#include "PlatformDependent/Xbox360/Source/GfxDevice/GfxXenonVBO.h" +#include "PlatformDependent/Xbox360/Source/Services/VideoPlayer.h" +#endif + +#if ENABLE_GFXDEVICE_REMOTE_PROCESS_CLIENT +#include <ppapi/cpp/instance.h> +#include "External/NPAPI2NaCl/Common/UnityInterfaces.h" +#include "PlatformDependent/PepperPlugin/UnityInstance.h" + +void *CreateSharedGfxDeviceAndBuffer(size_t size) +{ + struct UNITY_GfxDevice_1_0 *gfxInterface = (UNITY_GfxDevice_1_0*)pp::Module::Get()->GetBrowserInterface(UNITY_GFXDEVICE_INTERFACE_1_0); + PP_Resource res = gfxInterface->Create(GetUnityInstance().pp_instance(), size); + return gfxInterface->GetSharedMemoryBufferAddress(res); +} +#endif + +PROFILER_INFORMATION(gGfxWaitForPresentProf, "Gfx.WaitForPresent", kProfilerOverhead) + +class ClientGPUSkinningInfo : public GPUSkinningInfo +{ + friend class GfxDeviceClient; +private: + ClientGPUSkinningInfo(GPUSkinningInfo *realSkinInfo): GPUSkinningInfo(), m_realSkinInfo(realSkinInfo) {} + virtual ~ClientGPUSkinningInfo() {} + + GPUSkinningInfo *m_realSkinInfo; + +public: + virtual UInt32 GetVertexCount() { return m_realSkinInfo->GetVertexCount(); } + virtual UInt32 GetChannelMap() { return m_realSkinInfo->GetChannelMap(); } + virtual int GetStride() { return m_realSkinInfo->GetStride(); } + virtual VBO * GetDestVBO() { return m_DestVBO; } + virtual UInt32 GetBonesPerVertex() { return m_realSkinInfo->GetBonesPerVertex(); } + + /** Update vertex count */ + virtual void SetVertexCount(UInt32 count) { m_realSkinInfo->SetVertexCount(count); } + + /** Update channel map */ + virtual void SetChannelMap(UInt32 channelmap) { m_realSkinInfo->SetChannelMap(channelmap); } + + /** Update stride of the vertices in bytes (not including skin data). */ + virtual void SetStride(int stride) { m_realSkinInfo->SetStride(stride); } + + /** Update destination VBO */ + virtual void SetDestVBO(VBO *vbo) + { + m_DestVBO = vbo; + // realskininfo->m_destVBO will be updated lazily on the actual skinning call + } + + virtual void SetBonesPerVertex(UInt32 bones) + { + m_realSkinInfo->SetBonesPerVertex(bones); + } + + /** Threading support: Read from stream. */ + virtual void Read(ThreadedStreamBuffer& stream) + { + AssertBreak(false); + } + /** Threading support: Write to stream. */ + virtual void Write(ThreadedStreamBuffer& stream) + { + AssertBreak(false); + } + + /** Helper function for thread worker: clear the internal structures without releasing, + so the internal resources won't be double-released. */ + virtual void Clear() + { + AssertBreak(false); + } + +}; + + + + +GfxDevice* CreateClientGfxDevice(GfxDeviceRenderer renderer, UInt32 flags, size_t bufferSize, void *buffer) +{ + bool forceRef = (flags & kClientDeviceForceRef) != 0; + +#if !ENABLE_GFXDEVICE_REMOTE_PROCESS_CLIENT + if (flags & kClientDeviceUseRealDevice) + { + return CreateRealGfxDevice (renderer, forceRef); + } +#endif + + bool threaded = (flags & kClientDeviceThreaded) != 0; + bool clientProcess = (flags & kClientDeviceClientProcess) != 0; + bool workerProcess = (flags & kClientDeviceWorkerProcess) != 0; + + printf_console("GfxDevice: creating device client; threaded=%i\n", (int)threaded); + + // Threading mode must be set before creating device (so D3D9 gets correct flags) + SetGfxThreadingMode (threaded ? kGfxThreadingModeThreaded : kGfxThreadingModeNonThreaded); + + if (bufferSize == 0) + { +#if ENABLE_GFXDEVICE_REMOTE_PROCESS_CLIENT + // The native client uses a larger default size for the ring buffer, since it cannot + // flush the buffer at arbitrary times, so it needs to be big enough to hold complete + // data for texture upload commands. + bufferSize = 64*1024*1024; +#else + bufferSize = 8*1024*1024; +#endif + } + +#if ENABLE_GFXDEVICE_REMOTE_PROCESS_CLIENT + if (clientProcess) + buffer = CreateSharedGfxDeviceAndBuffer(bufferSize); +#endif + + GfxDeviceClient* device = UNITY_NEW_AS_ROOT(GfxDeviceClient(threaded, clientProcess, bufferSize, buffer), kMemGfxDevice, "GfxClientDevice", ""); + if (clientProcess) + { + device->SetRealGfxDevice (NULL); + device->QueryGraphicsCaps(); + return device; + } + + GfxDeviceWorker* worker = device->GetGfxDeviceWorker(); + if(renderer == kGfxRendererOpenGLES30) + SetGfxDevice(device); // Set this on GLES30 as we do stuff in OnDeviceCreated that requires this. Can't set it for all as it breaks NaCL build in teamcity. + GfxThreadableDevice* realDevice = worker->Startup(renderer, threaded && !workerProcess, forceRef); + + if (realDevice) + { + device->SetRealGfxDevice (realDevice); + device->AcquireThreadOwnership (); + realDevice->OnDeviceCreated (false); + device->ReleaseThreadOwnership (); + return device; + } + + // Failed to create threaded device + SetGfxThreadingMode (kGfxThreadingModeDirect); + + // Client device deletes worker + UNITY_DELETE(device, kMemGfxDevice); + return NULL; +} + +bool GfxDeviceWorkerProcessRunCommand() +{ + GfxDeviceClient& device = (GfxDeviceClient&)GetGfxDevice(); + GfxDeviceWorker* worker = device.GetGfxDeviceWorker(); + return worker->RunCommandIfDataIsAvailable(); +} + +void GfxDeviceClient::WaitForSignal () +{ +#if ENABLE_GFXDEVICE_REMOTE_PROCESS_CLIENT + struct UNITY_GfxDevice_1_0 *gfxInterface = (UNITY_GfxDevice_1_0*)pp::Module::Get()->GetBrowserInterface(UNITY_GFXDEVICE_INTERFACE_1_0); + return gfxInterface->WaitForSignal(0); +#else + if (m_DeviceWorker) + m_DeviceWorker->WaitForSignal(); +#endif +} + +void GfxDeviceClient::QueryGraphicsCaps() +{ + m_CommandQueue->WriteValueType<GfxCommand>(kGfxCmd_QueryGraphicsCaps); + + ReadbackData(m_ReadbackData); + + // no, really, we need to properly serialize this stuff with all the strings. this is just a hack to get running. + size_t offset = (char*)&gGraphicsCaps.vendorID - (char*)&gGraphicsCaps; + memcpy (&gGraphicsCaps.vendorID, m_ReadbackData.data(), std::min(m_ReadbackData.size(), sizeof(GraphicsCaps) - offset)); +} + + +GfxDeviceClient::GfxDeviceClient(bool threaded, bool clientProcess, size_t bufferSize, void *buffer) : + m_RealDevice(NULL), + m_Threaded(threaded), + m_Serialize(threaded), + m_RecordDepth(0), + m_MaxCallDepth(1), + m_DynamicVBO(NULL), + m_sRGBWrite(false) +{ + // Create stack of display lists (including "top" level) + m_DisplayListStack = new DisplayListContext[m_MaxCallDepth + 1]; + if (m_Threaded) + { + if (buffer) + m_DisplayListStack[0].commandQueue.CreateFromMemory(ThreadedStreamBuffer::kModeCrossProcess, bufferSize, buffer); + else + m_DisplayListStack[0].commandQueue.Create(ThreadedStreamBuffer::kModeThreaded, bufferSize); + m_DynamicVBO = new ThreadedDynamicVBO(*this); + } + for (int i = 1; i <= m_MaxCallDepth; i++) + m_DisplayListStack[i].commandQueue.Create(ThreadedStreamBuffer::kModeGrowable, 0); + m_CurrentContext = &m_DisplayListStack[0]; + m_CommandQueue = &m_CurrentContext->commandQueue; + m_InvertProjectionMatrix = false; + #if GFX_USES_VIEWPORT_OFFSET + m_ViewportOffset.Set(0.0f, 0.0f); + #endif + m_TransformState.Invalidate(m_BuiltinParamValues); + m_ScissorEnabled = -1; + m_PresentPending = false; + m_Wireframe = false; + m_CurrentTargetWidth = 0; + m_CurrentTargetHeight = 0; + m_CurrentWindowWidth = 0; + m_CurrentWindowHeight = 0; + m_ThreadOwnershipCount = 0; + m_CurrentCPUFence = 0; + m_PresentFrameID = 0; + if (clientProcess) + m_DeviceWorker = NULL; + else + m_DeviceWorker = new GfxDeviceWorker(4, m_CommandQueue); + + OnCreate(); + + { + ClientDeviceRenderSurface* color = new ClientDeviceRenderSurface(0, 0); + RenderSurfaceBase_InitColor(*color); + color->backBuffer = true; + color->internalHandle = m_RealDevice ? m_RealDevice->GetBackBufferColorSurface() : RenderSurfaceHandle(); + SetBackBufferColorSurface(color); + } + { + ClientDeviceRenderSurface* depth = new ClientDeviceRenderSurface(0, 0); + RenderSurfaceBase_InitDepth(*depth); + depth->backBuffer = true; + depth->internalHandle = m_RealDevice ? m_RealDevice->GetBackBufferDepthSurface() : RenderSurfaceHandle(); + SetBackBufferDepthSurface(depth); + } + +#if GFX_DEVICE_CLIENT_TRACK_TEXGEN + posForTexGen = 0; + nrmForTexGen = 0; + CompileTimeAssert(sizeof(posForTexGen) * 8 == kMaxSupportedTextureUnitsGLES, "posForTexGen should have enough bits for tex units"); + CompileTimeAssert(sizeof(nrmForTexGen) * 8 == kMaxSupportedTextureUnitsGLES, "nrmForTexGen should have enough bits for tex units"); +#endif +} + +GfxDeviceClient::~GfxDeviceClient() +{ + CheckMainThread(); + if (m_Threaded && m_RealDevice) + { + m_CommandQueue->WriteValueType<GfxCommand>(kGfxCmd_Quit); + SubmitCommands(); + WaitForSignal(); + GFXDEVICE_LOCKSTEP_CLIENT(); + } + // m_CommandQueue was not allocated + m_CommandQueue = NULL; + delete[] m_DisplayListStack; + if (m_Threaded) + delete m_DynamicVBO; + delete m_DeviceWorker; +} + +void GfxDeviceClient::InvalidateState() +{ + CheckMainThread(); + DebugAssert(!IsRecording()); + m_TransformState.Invalidate(m_BuiltinParamValues); + m_FogParams.Invalidate(); + if (m_Serialize) + { + m_CommandQueue->WriteValueType<GfxCommand>(kGfxCmd_InvalidateState); + GFXDEVICE_LOCKSTEP_CLIENT(); + } + else + m_RealDevice->InvalidateState(); +} + +#if GFX_DEVICE_VERIFY_ENABLE +void GfxDeviceClient::VerifyState() +{ + CheckMainThread(); + if (m_Serialize) + { + m_CommandQueue->WriteValueType<GfxCommand>(kGfxCmd_VerifyState); + SubmitCommands(); + GFXDEVICE_LOCKSTEP_CLIENT(); + } + else + m_RealDevice->VerifyState(); +} +#endif + + +void GfxDeviceClient::SetMaxBufferedFrames (int bufferSize) +{ + CheckMainThread(); + GfxDevice::SetMaxBufferedFrames(bufferSize); + if (m_Serialize) + { + m_CommandQueue->WriteValueType<GfxCommand>(kGfxCmd_SetMaxBufferedFrames); + m_CommandQueue->WriteValueType<int>(bufferSize); + GFXDEVICE_LOCKSTEP_CLIENT(); + } + else + m_RealDevice->SetMaxBufferedFrames(bufferSize); +} + + +void GfxDeviceClient::Clear( UInt32 clearFlags, const float color[4], float depth, int stencil ) +{ + CheckMainThread(); + + // mark cleared surfaces as "no contents" if we're tracking that + if (GetFrameStats().m_StatsEnabled) + { + if (clearFlags & kGfxClearColor) + { + for (int i = 0; i < kMaxSupportedRenderTargets; ++i) + { + if (!m_ActiveRenderColorSurfaces[i].IsValid ()) + continue; + ClientDeviceRenderSurface* colorSurf = (ClientDeviceRenderSurface*)m_ActiveRenderColorSurfaces[i].object; + colorSurf->state = ClientDeviceRenderSurface::kCleared; + } + } + if ((clearFlags & kGfxClearDepthStencil) && m_ActiveRenderDepthSurface.IsValid ()) + { + ClientDeviceRenderSurface* depthSurf = (ClientDeviceRenderSurface*)m_ActiveRenderDepthSurface.object; + if (depthSurf) + depthSurf->state = ClientDeviceRenderSurface::kCleared; + } + } + + if (m_Serialize) + { + m_CommandQueue->WriteValueType<GfxCommand>(kGfxCmd_Clear); + GfxCmdClear clear = { clearFlags, Vector4f(color), depth, stencil }; + m_CommandQueue->WriteValueType<GfxCmdClear>(clear); + SubmitCommands(); + GFXDEVICE_LOCKSTEP_CLIENT(); + } + else + m_RealDevice->Clear(clearFlags, color, depth, stencil); +} + +void GfxDeviceClient::SetUserBackfaceMode( bool enable ) +{ + CheckMainThread(); + if (m_Serialize) + { + m_CommandQueue->WriteValueType<GfxCommand>(kGfxCmd_SetUserBackfaceMode); + m_CommandQueue->WriteValueType<GfxCmdBool>(enable); + GFXDEVICE_LOCKSTEP_CLIENT(); + } + else + m_RealDevice->SetUserBackfaceMode(enable); +} + +void GfxDeviceClient::SetWireframe(bool wire) +{ + CheckMainThread(); + m_Wireframe = wire; + if (m_Serialize) + { + m_CommandQueue->WriteValueType<GfxCommand>(kGfxCmd_SetWireframe); + m_CommandQueue->WriteValueType<GfxCmdBool>(wire); + GFXDEVICE_LOCKSTEP_CLIENT(); + } + else + m_RealDevice->SetWireframe(wire); +} + +bool GfxDeviceClient::GetWireframe() const +{ + return m_Wireframe; +} + + +void GfxDeviceClient::SetInvertProjectionMatrix( bool enable ) +{ + CheckMainThread(); + m_InvertProjectionMatrix = enable; + if (m_Serialize) + { + m_CommandQueue->WriteValueType<GfxCommand>(kGfxCmd_SetInvertProjectionMatrix); + m_CommandQueue->WriteValueType<GfxCmdBool>(enable); + GFXDEVICE_LOCKSTEP_CLIENT(); + } + else + m_RealDevice->SetInvertProjectionMatrix(enable); +} + +bool GfxDeviceClient::GetInvertProjectionMatrix() const +{ + CheckMainThread(); + return m_InvertProjectionMatrix; +} + +#if GFX_USES_VIEWPORT_OFFSET +void GfxDeviceClient::SetViewportOffset( float x, float y ) +{ + CheckMainThread(); + m_ViewportOffset = Vector2f(x, y); + if (m_Serialize) + { + m_CommandQueue->WriteValueType<GfxCommand>(kGfxCmd_SetViewportOffset); + m_CommandQueue->WriteValueType<Vector2f>(m_ViewportOffset); + GFXDEVICE_LOCKSTEP_CLIENT(); + } + else + m_RealDevice->SetViewportOffset(x, y); +} + +void GfxDeviceClient::GetViewportOffset( float &x, float &y ) const +{ + x = m_ViewportOffset.x; + y = m_ViewportOffset.y; +} +#endif + +DeviceBlendState* GfxDeviceClient::CreateBlendState(const GfxBlendState& state) +{ + CheckMainThread(); + SET_ALLOC_OWNER(this); + DebugAssert(!IsRecording()); + std::pair<CachedBlendStates::iterator, bool> added = m_CachedBlendStates.insert(std::make_pair(state, ClientDeviceBlendState(state))); + ClientDeviceBlendState* result = &added.first->second; + if (!added.second) + return result; + + if (m_Serialize) + { + m_CommandQueue->WriteValueType<GfxCommand>(kGfxCmd_CreateBlendState); +#if ENABLE_GFXDEVICE_REMOTE_PROCESS + result->internalState = m_BlendStateMapper.CreateID(); + m_CommandQueue->WriteValueType<ClientDeviceBlendState>(*result); +#else + m_CommandQueue->WriteValueType<ClientDeviceBlendState*>(result); +#endif + SubmitCommands(); + GFXDEVICE_LOCKSTEP_CLIENT(); + } +#if !ENABLE_GFXDEVICE_REMOTE_PROCESS + else + result->internalState = m_RealDevice->CreateBlendState(state); +#endif + + return result; +} + +DeviceDepthState* GfxDeviceClient::CreateDepthState(const GfxDepthState& state) +{ + CheckMainThread(); + SET_ALLOC_OWNER(this); + DebugAssert(!IsRecording()); + std::pair<CachedDepthStates::iterator, bool> added = m_CachedDepthStates.insert(std::make_pair(state, ClientDeviceDepthState(state))); + ClientDeviceDepthState* result = &added.first->second; + if (!added.second) + return result; + + if (m_Serialize) + { + m_CommandQueue->WriteValueType<GfxCommand>(kGfxCmd_CreateDepthState); +#if ENABLE_GFXDEVICE_REMOTE_PROCESS + result->internalState = m_DepthStateMapper.CreateID(); + m_CommandQueue->WriteValueType<ClientDeviceDepthState>(*result); +#else + m_CommandQueue->WriteValueType<ClientDeviceDepthState*>(result); +#endif + SubmitCommands(); + GFXDEVICE_LOCKSTEP_CLIENT(); + } +#if !ENABLE_GFXDEVICE_REMOTE_PROCESS + else + result->internalState = m_RealDevice->CreateDepthState(state); +#endif + return result; +} + +DeviceStencilState* GfxDeviceClient::CreateStencilState(const GfxStencilState& state) +{ + CheckMainThread(); + DebugAssert(!IsRecording()); + SET_ALLOC_OWNER(this); + std::pair<CachedStencilStates::iterator, bool> added = m_CachedStencilStates.insert(std::make_pair(state, ClientDeviceStencilState(state))); + ClientDeviceStencilState* result = &added.first->second; + if (!added.second) + return result; + + if (m_Serialize) + { + m_CommandQueue->WriteValueType<GfxCommand>(kGfxCmd_CreateStencilState); +#if ENABLE_GFXDEVICE_REMOTE_PROCESS + result->internalState = m_StencilStateMapper.CreateID(); + m_CommandQueue->WriteValueType<ClientDeviceStencilState>(*result); +#else + m_CommandQueue->WriteValueType<ClientDeviceStencilState*>(result); +#endif + SubmitCommands(); + GFXDEVICE_LOCKSTEP_CLIENT(); + } +#if !ENABLE_GFXDEVICE_REMOTE_PROCESS + else + result->internalState = m_RealDevice->CreateStencilState(state); +#endif + return result; +} + +DeviceRasterState* GfxDeviceClient::CreateRasterState(const GfxRasterState& state) +{ + CheckMainThread(); + DebugAssert(!IsRecording()); + SET_ALLOC_OWNER(this); + std::pair<CachedRasterStates::iterator, bool> added = m_CachedRasterStates.insert(std::make_pair(state, ClientDeviceRasterState(state))); + ClientDeviceRasterState* result = &added.first->second; + if (!added.second) + return result; + + if (m_Serialize) + { + m_CommandQueue->WriteValueType<GfxCommand>(kGfxCmd_CreateRasterState); +#if ENABLE_GFXDEVICE_REMOTE_PROCESS + result->internalState = m_RasterStateMapper.CreateID(); + m_CommandQueue->WriteValueType<ClientDeviceRasterState>(*result); +#else + m_CommandQueue->WriteValueType<ClientDeviceRasterState*>(result); +#endif + SubmitCommands(); + GFXDEVICE_LOCKSTEP_CLIENT(); + } +#if !ENABLE_GFXDEVICE_REMOTE_PROCESS + else + result->internalState = m_RealDevice->CreateRasterState(state); +#endif + + return result; +} + +void GfxDeviceClient::RecordSetBlendState(const DeviceBlendState* state, const ShaderLab::FloatVal& alphaRef, const ShaderLab::PropertySheet* props) +{ + CheckMainThread(); + DebugAssert(IsRecording()); + const ClientDeviceBlendState* clientState = static_cast<const ClientDeviceBlendState*>(state); + m_CommandQueue->WriteValueType<GfxCommand>(kGfxCmd_SetBlendState); + m_CommandQueue->WriteValueType<const ClientDeviceBlendState*>(clientState); + float* dest = m_CommandQueue->GetWritePointer<float>(); + // Must call GetBuffer() after GetWritePointer() since it might be reallocated! + const void* bufferStart = m_CommandQueue->GetBuffer(); + m_CurrentContext->patchInfo.AddPatchableFloat(alphaRef, *dest, bufferStart, props); + GFXDEVICE_LOCKSTEP_CLIENT(); +} + +void GfxDeviceClient::SetBlendState(const DeviceBlendState* state, float alphaRef) +{ + CheckMainThread(); + const ClientDeviceBlendState* clientState = static_cast<const ClientDeviceBlendState*>(state); + if (m_Serialize) + { + m_CommandQueue->WriteValueType<GfxCommand>(kGfxCmd_SetBlendState); +#if ENABLE_GFXDEVICE_REMOTE_PROCESS + m_CommandQueue->WriteValueType<const ClientDeviceBlendState>(*clientState); +#else + m_CommandQueue->WriteValueType<const ClientDeviceBlendState*>(clientState); +#endif + m_CommandQueue->WriteValueType<float>(alphaRef); + GFXDEVICE_LOCKSTEP_CLIENT(); + } +#if !ENABLE_GFXDEVICE_REMOTE_PROCESS + else + m_RealDevice->SetBlendState(clientState->internalState, alphaRef); +#endif +} + +void GfxDeviceClient::SetDepthState(const DeviceDepthState* state) +{ + CheckMainThread(); + const ClientDeviceDepthState* clientState = static_cast<const ClientDeviceDepthState*>(state); + if (m_Serialize) + { + m_CommandQueue->WriteValueType<GfxCommand>(kGfxCmd_SetDepthState); +#if ENABLE_GFXDEVICE_REMOTE_PROCESS + m_CommandQueue->WriteValueType<const ClientDeviceDepthState>(*clientState); +#else + m_CommandQueue->WriteValueType<const ClientDeviceDepthState*>(clientState); +#endif + GFXDEVICE_LOCKSTEP_CLIENT(); + } +#if !ENABLE_GFXDEVICE_REMOTE_PROCESS + else + m_RealDevice->SetDepthState(clientState->internalState); +#endif +} + +void GfxDeviceClient::SetStencilState(const DeviceStencilState* state, int stencilRef) +{ + CheckMainThread(); + const ClientDeviceStencilState* clientState = static_cast<const ClientDeviceStencilState*>(state); + if (m_Serialize) + { + m_CommandQueue->WriteValueType<GfxCommand>(kGfxCmd_SetStencilState); +#if ENABLE_GFXDEVICE_REMOTE_PROCESS + m_CommandQueue->WriteValueType<const ClientDeviceStencilState>(*clientState); +#else + m_CommandQueue->WriteValueType<const ClientDeviceStencilState*>(clientState); +#endif + m_CommandQueue->WriteValueType<int>(stencilRef); + GFXDEVICE_LOCKSTEP_CLIENT(); + } +#if !ENABLE_GFXDEVICE_REMOTE_PROCESS + else + m_RealDevice->SetStencilState(clientState->internalState, stencilRef); +#endif +} + +#if UNITY_XENON +void GfxDeviceClient::SetNullPixelShader() +{ + CheckMainThread(); + if (m_Serialize) + { + m_CommandQueue->WriteValueType<GfxCommand>(kGfxCmd_SetNullPixelShader); + GFXDEVICE_LOCKSTEP_CLIENT(); + } + else + m_RealDevice->SetNullPixelShader(); +} + +void GfxDeviceClient::SetHiZEnable( const HiZstate hiz ) +{ + CheckMainThread(); + if (m_Serialize) + { + m_CommandQueue->WriteValueType<GfxCommand>(kGfxCmd_EnableHiZ); + m_CommandQueue->WriteValueType<HiZstate>( hiz ); + GFXDEVICE_LOCKSTEP_CLIENT(); + } + else + m_RealDevice->SetHiZEnable( hiz ); +} + +void GfxDeviceClient::SetHiStencilState( const bool hiStencilEnable, const bool hiStencilWriteEnable, const int hiStencilRef, const CompareFunction cmpFunc ) +{ + CheckMainThread(); + if (m_Serialize) + { + m_CommandQueue->WriteValueType<GfxCommand>(kGfxCmd_SetHiStencilState); + m_CommandQueue->WriteValueType<bool>(hiStencilEnable); + m_CommandQueue->WriteValueType<bool>(hiStencilWriteEnable); + m_CommandQueue->WriteValueType<int>(hiStencilRef); + m_CommandQueue->WriteValueType<CompareFunction>(cmpFunc); + GFXDEVICE_LOCKSTEP_CLIENT(); + } + else + m_RealDevice->SetHiStencilState( hiStencilEnable, hiStencilWriteEnable, hiStencilRef, cmpFunc ); +} + +void GfxDeviceClient::HiStencilFlush( const HiSflush flushtype ) +{ + CheckMainThread(); + if (m_Serialize) + { + m_CommandQueue->WriteValueType<GfxCommand>(kGfxCmd_HiStencilFlush); + m_CommandQueue->WriteValueType<HiSflush>(flushtype); + GFXDEVICE_LOCKSTEP_CLIENT(); + } + else + m_RealDevice->HiStencilFlush(flushtype); +} +#endif + +void GfxDeviceClient::SetRasterState(const DeviceRasterState* state) +{ + CheckMainThread(); + const ClientDeviceRasterState* clientState = static_cast<const ClientDeviceRasterState*>(state); + if (m_Serialize) + { + m_CommandQueue->WriteValueType<GfxCommand>(kGfxCmd_SetRasterState); +#if ENABLE_GFXDEVICE_REMOTE_PROCESS + m_CommandQueue->WriteValueType<const ClientDeviceRasterState>(*clientState); +#else + m_CommandQueue->WriteValueType<const ClientDeviceRasterState*>(clientState); +#endif + GFXDEVICE_LOCKSTEP_CLIENT(); + } +#if !ENABLE_GFXDEVICE_REMOTE_PROCESS + else + m_RealDevice->SetRasterState(clientState->internalState); +#endif +} + +void GfxDeviceClient::SetSRGBWrite (bool enable) +{ + CheckMainThread(); + DebugAssert(!IsRecording()); + m_sRGBWrite = enable; + if (m_Serialize) + { + m_CommandQueue->WriteValueType<GfxCommand>(kGfxCmd_SetSRGBState); + m_CommandQueue->WriteValueType<GfxCmdBool>(enable); + GFXDEVICE_LOCKSTEP_CLIENT(); + } + else + m_RealDevice->SetSRGBWrite(enable); +} + +bool GfxDeviceClient::GetSRGBWrite () +{ + CheckMainThread(); + return m_sRGBWrite; +} + +void GfxDeviceClient::SetWorldMatrix( const float matrix[16] ) +{ + CheckMainThread(); + DebugAssert(!IsRecording()); + m_TransformState.dirtyFlags |= TransformState::kWorldDirty; + memcpy(m_TransformState.worldMatrix.GetPtr(), matrix, 16 * sizeof(float)); + if (m_Serialize) + { + m_CommandQueue->WriteValueType<GfxCommand>(kGfxCmd_SetWorldMatrix); + m_CommandQueue->WriteValueType<Matrix4x4f>(m_TransformState.worldMatrix); + GFXDEVICE_LOCKSTEP_CLIENT(); + } + else + m_RealDevice->SetWorldMatrix(matrix); +} + +void GfxDeviceClient::SetViewMatrix( const float matrix[16] ) +{ + CheckMainThread(); + DebugAssert(!IsRecording()); + m_TransformState.SetViewMatrix (matrix, m_BuiltinParamValues); + if (m_Serialize) + { + m_CommandQueue->WriteValueType<GfxCommand>(kGfxCmd_SetViewMatrix); + m_CommandQueue->WriteValueType<Matrix4x4f>(m_BuiltinParamValues.GetMatrixParam(kShaderMatView)); + GFXDEVICE_LOCKSTEP_CLIENT(); + } + else + m_RealDevice->SetViewMatrix(matrix); +} + +void GfxDeviceClient::SetProjectionMatrix (const Matrix4x4f& matrix) +{ + CheckMainThread(); + DebugAssert(!IsRecording()); + m_TransformState.dirtyFlags |= TransformState::kProjDirty; + Matrix4x4f& m = m_BuiltinParamValues.GetWritableMatrixParam(kShaderMatProj); + CopyMatrix (matrix.GetPtr(), m.GetPtr()); + CopyMatrix (matrix.GetPtr(), m_TransformState.projectionMatrixOriginal.GetPtr()); + CalculateDeviceProjectionMatrix (m, m_UsesOpenGLTextureCoords, m_InvertProjectionMatrix); + if (m_Serialize) + { + m_CommandQueue->WriteValueType<GfxCommand>(kGfxCmd_SetProjectionMatrix); + m_CommandQueue->WriteValueType<Matrix4x4f>(matrix); + GFXDEVICE_LOCKSTEP_CLIENT(); + } + else + m_RealDevice->SetProjectionMatrix(matrix); +} + +void GfxDeviceClient::GetMatrix( float outMatrix[16] ) const +{ + m_TransformState.UpdateWorldViewMatrix(m_BuiltinParamValues); + memcpy(outMatrix, m_TransformState.worldViewMatrix.GetPtr(), 16 * sizeof(float)); +} + +const float* GfxDeviceClient::GetWorldMatrix() const +{ + return m_TransformState.worldMatrix.GetPtr(); +} + +const float* GfxDeviceClient::GetViewMatrix() const +{ + return m_BuiltinParamValues.GetMatrixParam(kShaderMatView).GetPtr(); +} + +const float* GfxDeviceClient::GetProjectionMatrix() const +{ + return m_TransformState.projectionMatrixOriginal.GetPtr(); +} + +const float* GfxDeviceClient::GetDeviceProjectionMatrix() const +{ + return m_BuiltinParamValues.GetMatrixParam(kShaderMatProj).GetPtr(); +} + +void GfxDeviceClient::SetInverseScale( float invScale ) +{ + CheckMainThread(); + DebugAssert(!IsRecording()); + GfxDevice::SetInverseScale(invScale); + if (m_Serialize) + { + m_CommandQueue->WriteValueType<GfxCommand>(kGfxCmd_SetInverseScale); + m_CommandQueue->WriteValueType<float>(invScale); + GFXDEVICE_LOCKSTEP_CLIENT(); + } + else + m_RealDevice->SetInverseScale(invScale); +} + +void GfxDeviceClient::SetNormalizationBackface( NormalizationMode mode, bool backface ) +{ + CheckMainThread(); + if (m_Serialize) + { + m_CommandQueue->WriteValueType<GfxCommand>(kGfxCmd_SetNormalizationBackface); + GfxCmdSetNormalizationBackface data = { mode, backface}; + m_CommandQueue->WriteValueType<GfxCmdSetNormalizationBackface>(data); + GFXDEVICE_LOCKSTEP_CLIENT(); + } + else + m_RealDevice->SetNormalizationBackface(mode, backface); +} + +void GfxDeviceClient::SetFFLighting( bool on, bool separateSpecular, ColorMaterialMode colorMaterial ) +{ + CheckMainThread(); + if (m_Serialize) + { + m_CommandQueue->WriteValueType<GfxCommand>(kGfxCmd_SetFFLighting); + GfxCmdSetFFLighting data = { on, separateSpecular, colorMaterial }; + m_CommandQueue->WriteValueType<GfxCmdSetFFLighting>(data); + GFXDEVICE_LOCKSTEP_CLIENT(); + } + else + m_RealDevice->SetFFLighting(on, separateSpecular, colorMaterial); +} + +void GfxDeviceClient::RecordSetMaterial( const ShaderLab::VectorVal& ambient, const ShaderLab::VectorVal& diffuse, const ShaderLab::VectorVal& specular, const ShaderLab::VectorVal& emissive, const ShaderLab::FloatVal& shininess, const ShaderLab::PropertySheet* props ) +{ + CheckMainThread(); + DebugAssert(IsRecording()); + m_CommandQueue->WriteValueType<GfxCommand>(kGfxCmd_SetMaterial); + GfxMaterialParams* dest = m_CommandQueue->GetWritePointer<GfxMaterialParams>(); + // Must call GetBuffer() after GetWritePointer() since it might be reallocated! + const void* bufferStart = m_CommandQueue->GetBuffer(); + GfxPatchInfo& patchInfo = m_CurrentContext->patchInfo; + patchInfo.AddPatchableVector(ambient, dest->ambient, bufferStart, props); + patchInfo.AddPatchableVector(diffuse, dest->diffuse, bufferStart, props); + patchInfo.AddPatchableVector(specular, dest->specular, bufferStart, props); + patchInfo.AddPatchableVector(emissive, dest->emissive, bufferStart, props); + patchInfo.AddPatchableFloat(shininess, dest->shininess, bufferStart, props); + GFXDEVICE_LOCKSTEP_CLIENT(); +} + +void GfxDeviceClient::SetMaterial( const float ambient[4], const float diffuse[4], const float specular[4], const float emissive[4], const float shininess ) +{ + CheckMainThread(); + if (m_Serialize) + { + m_CommandQueue->WriteValueType<GfxCommand>(kGfxCmd_SetMaterial); + GfxMaterialParams mat = { Vector4f(ambient), Vector4f(diffuse), Vector4f(specular), Vector4f(emissive), shininess }; + m_CommandQueue->WriteValueType<GfxMaterialParams>(mat); + GFXDEVICE_LOCKSTEP_CLIENT(); + } + else + m_RealDevice->SetMaterial(ambient, diffuse, specular, emissive, shininess); +} + +void GfxDeviceClient::RecordSetColor( const ShaderLab::VectorVal& color, const ShaderLab::PropertySheet* props ) +{ + CheckMainThread(); + DebugAssert(IsRecording()); + m_CommandQueue->WriteValueType<GfxCommand>(kGfxCmd_SetColor); + Vector4f* dest = m_CommandQueue->GetWritePointer<Vector4f>(); + // Must call GetBuffer() after GetWritePointer() since it might be reallocated! + const void* bufferStart = m_CommandQueue->GetBuffer(); + m_CurrentContext->patchInfo.AddPatchableVector(color, *dest, bufferStart, props); + GFXDEVICE_LOCKSTEP_CLIENT(); +} + +void GfxDeviceClient::SetColor( const float color[4] ) +{ + CheckMainThread(); + if (m_Serialize) + { + m_CommandQueue->WriteValueType<GfxCommand>(kGfxCmd_SetColor); + m_CommandQueue->WriteValueType<Vector4f>(Vector4f(color)); + GFXDEVICE_LOCKSTEP_CLIENT(); + } + else + m_RealDevice->SetColor(color); +} + +void GfxDeviceClient::SetViewport( int x, int y, int width, int height ) +{ + CheckMainThread(); + DebugAssert(!IsRecording()); + m_Viewport.x = x; + m_Viewport.y = y; + m_Viewport.width = width; + m_Viewport.height = height; + if (m_Serialize) + { + m_CommandQueue->WriteValueType<GfxCommand>(kGfxCmd_SetViewport); + m_CommandQueue->WriteValueType<ClientDeviceRect>(m_Viewport); + GFXDEVICE_LOCKSTEP_CLIENT(); + } + else + m_RealDevice->SetViewport(x, y, width, height); +} + +void GfxDeviceClient::GetViewport( int* values ) const +{ + values[0] = m_Viewport.x; + values[1] = m_Viewport.y; + values[2] = m_Viewport.width; + values[3] = m_Viewport.height; +} + +void GfxDeviceClient::SetScissorRect( int x, int y, int width, int height ) +{ + CheckMainThread(); + DebugAssert(!IsRecording()); + m_ScissorRect.x = x; + m_ScissorRect.y = y; + m_ScissorRect.width = width; + m_ScissorRect.height = height; + m_ScissorEnabled = 1; + if (m_Serialize) + { + m_CommandQueue->WriteValueType<GfxCommand>(kGfxCmd_SetScissorRect); + m_CommandQueue->WriteValueType<ClientDeviceRect>(m_ScissorRect); + GFXDEVICE_LOCKSTEP_CLIENT(); + } + else + m_RealDevice->SetScissorRect(x, y, width, height); +} + +void GfxDeviceClient::DisableScissor() +{ + CheckMainThread(); + DebugAssert(!IsRecording()); + m_ScissorEnabled = 0; + if (m_Serialize) + { + m_CommandQueue->WriteValueType<GfxCommand>(kGfxCmd_DisableScissor); + GFXDEVICE_LOCKSTEP_CLIENT(); + } + else + m_RealDevice->DisableScissor(); +} + +bool GfxDeviceClient::IsScissorEnabled() const +{ + return m_ScissorEnabled == 1; +} + +void GfxDeviceClient::GetScissorRect( int values[4] ) const +{ + values[0] = m_ScissorRect.x; + values[1] = m_ScissorRect.y; + values[2] = m_ScissorRect.width; + values[3] = m_ScissorRect.height; +} + +TextureCombinersHandle GfxDeviceClient::CreateTextureCombiners( int count, const ShaderLab::TextureBinding* texEnvs, const ShaderLab::PropertySheet* props, bool hasVertexColorOrLighting, bool usesAddSpecular ) +{ + SET_ALLOC_OWNER(NULL); // Not set to this since these are leaked. Some shaders are created staticly and are not cleaned up. + CheckMainThread(); + + if (count > gGraphicsCaps.maxTexUnits) + return TextureCombinersHandle( NULL ); + +#if !ENABLE_GFXDEVICE_REMOTE_PROCESS + for (int i = 0; i < count; i++) + if (!m_RealDevice->IsCombineModeSupported( texEnvs[i].m_CombColor )) + return TextureCombinersHandle( NULL ); + + // check texgen modes & texture dimension are supported + for (int i = 0; i < count; i++) + { + TextureDimension texDim; + TexGenMode texGen; + ShaderLab::shaderprops::GetTexEnvInfo( props, texEnvs[i].m_TextureName, texDim, texGen ); + if (!ShaderLab::IsTexEnvSupported( texEnvs[i].m_TextureName, texDim, texGen )) + return TextureCombinersHandle( NULL ); + } +#endif + + ClientDeviceTextureCombiners* combiners = UNITY_NEW(ClientDeviceTextureCombiners, kMemGfxThread); + combiners->bindings = (ShaderLab::TextureBinding*)UNITY_MALLOC(kMemGfxThread,sizeof(ShaderLab::TextureBinding)*count); + for(int i = 0; i < count; i++) new ((void*)(&combiners->bindings[i])) ShaderLab::TextureBinding; + combiners->count = count; + for (int i = 0; i < count; i++) + combiners->bindings[i] = texEnvs[i]; + + if (m_Serialize) + { + // Don't want to create texture combiners from a display list + m_CurrentContext->recordFailed = true; + m_CommandQueue->WriteValueType<GfxCommand>(kGfxCmd_CreateTextureCombiners); +#if ENABLE_GFXDEVICE_REMOTE_PROCESS + combiners->internalHandle = m_TextureCombinerMapper.CreateID(); + m_CommandQueue->WriteValueType<ClientIDMapper::ClientID>(combiners->internalHandle); + m_CommandQueue->WriteValueType<int>(combiners->count); + for (int i = 0; i < count; i++) + m_CommandQueue->WriteValueType<ShaderLab::TextureBinding>(combiners->bindings[i]); +#else + m_CommandQueue->WriteValueType<ClientDeviceTextureCombiners*>(combiners); +#endif + GfxCmdCreateTextureCombiners texcomb = { count, hasVertexColorOrLighting, usesAddSpecular }; + m_CommandQueue->WriteValueType<GfxCmdCreateTextureCombiners>(texcomb); + GFXDEVICE_LOCKSTEP_CLIENT(); + } +#if !ENABLE_GFXDEVICE_REMOTE_PROCESS + else + combiners->internalHandle = m_RealDevice->CreateTextureCombiners(count, texEnvs, props, hasVertexColorOrLighting, usesAddSpecular); +#endif + + return TextureCombinersHandle( combiners ); +} +void GfxDeviceClient::DeleteTextureCombiners( TextureCombinersHandle& textureCombiners ) +{ + CheckMainThread(); + if (!textureCombiners.IsValid()) + return; + + ClientDeviceTextureCombiners* combiners = static_cast<ClientDeviceTextureCombiners*>(textureCombiners.object); + + if (m_Serialize) + { + // Must delete when message received + m_CommandQueue->WriteValueType<GfxCommand>(kGfxCmd_DeleteTextureCombiners); +#if ENABLE_GFXDEVICE_REMOTE_PROCESS + m_CommandQueue->WriteValueType<ClientIDMapper::ClientID>(combiners->internalHandle); + m_CommandQueue->WriteValueType<int>(combiners->count); + delete[] combiners->bindings; + delete combiners; +#else + m_CommandQueue->WriteValueType<ClientDeviceTextureCombiners*>(combiners); + textureCombiners.Reset(); +#endif + GFXDEVICE_LOCKSTEP_CLIENT(); + } + else + { + + for(int i = 0; i < combiners->count; i++) (&combiners->bindings[i])->~TextureBinding(); + UNITY_FREE(kMemGfxThread, combiners->bindings); + UNITY_DELETE(combiners,kMemGfxThread); + } +} + +void GfxDeviceClient::SetTextureCombiners( TextureCombinersHandle textureCombiners, const ShaderLab::PropertySheet* props ) +{ + CheckMainThread(); + if (!textureCombiners.IsValid()) + return; + + ClientDeviceTextureCombiners* combiners = static_cast<ClientDeviceTextureCombiners*>(textureCombiners.object); + +#if GFX_DEVICE_CLIENT_TRACK_TEXGEN + for(int i = 0, n = combiners->count ; i < n ; ++i) + SetTexGen(i, GetTexEnvForBinding(combiners->bindings[i], props)->GetTexGen()); + for(int i = combiners->count ; i < kMaxSupportedTextureUnitsGLES ; ++i) + DropTexGen(i); +#endif + + if (m_Serialize) + { + int count = combiners->count; + m_CommandQueue->WriteValueType<GfxCommand>(kGfxCmd_SetTextureCombiners); +#if ENABLE_GFXDEVICE_REMOTE_PROCESS + m_CommandQueue->WriteValueType<ClientIDMapper::ClientID>(combiners->internalHandle); + m_CommandQueue->WriteValueType<int>(combiners->count); +#else + m_CommandQueue->WriteValueType<ClientDeviceTextureCombiners*>(combiners); +#endif + void* data = m_CommandQueue->GetWriteDataPointer(count * sizeof(TexEnvData), ALIGN_OF(TexEnvData)); + // Must call GetBuffer() after GetWriteDataPointer() since it might be reallocated! + const UInt8* bufferStart = IsRecording() ? static_cast<const UInt8*>(m_CommandQueue->GetBuffer()) : NULL; + TexEnvData* dest = static_cast<TexEnvData*>(data); + for (int i = 0; i < count; i++) + { + using namespace ShaderLab::shaderprops; + ShaderLab::TextureBinding& binding = combiners->bindings[i]; + if (IsRecording()) + { + if (!m_CurrentContext->patchInfo.AddPatchableTexEnv(binding.m_TextureName, binding.m_MatrixName, + kTexDimAny, &dest[i], bufferStart, props)) + m_CurrentContext->recordFailed = true; + } + else + { + ShaderLab::TexEnv* te = GetTexEnvForBinding(binding, props); + Assert(te != NULL); + te->PrepareData(binding.m_TextureName.index, binding.m_MatrixName, props, &dest[i]); + } + } + data = m_CommandQueue->GetWriteDataPointer(count * sizeof(Vector4f), ALIGN_OF(Vector4f)); + Vector4f* texColors = static_cast<Vector4f*>(data); + for (int i = 0; i < count; i++) + { + const ShaderLab::TextureBinding& binding = combiners->bindings[i]; + texColors[i] = binding.GetTexColor().Get (props); + } + SubmitCommands(); + GFXDEVICE_LOCKSTEP_CLIENT(); + } +#if !ENABLE_GFXDEVICE_REMOTE_PROCESS + else + m_RealDevice->SetTextureCombiners(combiners->internalHandle, props); +#endif +} + +void GfxDeviceClient::SetTexture (ShaderType shaderType, int unit, int samplerUnit, TextureID texture, TextureDimension dim, float bias) +{ + CheckMainThread(); + DebugAssert( dim >= kTexDim2D && dim <= kTexDimCUBE ); + if (m_Serialize) + { + m_CommandQueue->WriteValueType<GfxCommand>(kGfxCmd_SetTexture); + GfxCmdSetTexture tex = {shaderType, unit, samplerUnit, texture, dim, bias}; + m_CommandQueue->WriteValueType<GfxCmdSetTexture>(tex); + GFXDEVICE_LOCKSTEP_CLIENT(); + } + else + m_RealDevice->SetTexture (shaderType, unit, samplerUnit, texture, dim, bias); +} + +void GfxDeviceClient::SetTextureParams( TextureID texture, TextureDimension texDim, TextureFilterMode filter, TextureWrapMode wrap, int anisoLevel, bool hasMipMap, TextureColorSpace colorSpace ) +{ + CheckMainThread(); + if (m_Serialize) + { + m_CommandQueue->WriteValueType<GfxCommand>(kGfxCmd_SetTextureParams); + GfxCmdSetTextureParams params = { texture, texDim, filter, wrap, anisoLevel, hasMipMap, colorSpace }; + m_CommandQueue->WriteValueType<GfxCmdSetTextureParams>(params); + SubmitCommands(); + GFXDEVICE_LOCKSTEP_CLIENT(); + } + else + m_RealDevice->SetTextureParams(texture, texDim, filter, wrap, anisoLevel, hasMipMap, colorSpace); +} + +void GfxDeviceClient::SetTextureTransform( int unit, TextureDimension dim, TexGenMode texGen, bool identity, const float matrix[16]) +{ + CheckMainThread(); + +#if GFX_DEVICE_CLIENT_TRACK_TEXGEN + SetTexGen(unit, texGen); +#endif + + if (m_Serialize) + { + m_CommandQueue->WriteValueType<GfxCommand>(kGfxCmd_SetTextureTransform); + GfxCmdSetTextureTransform trans = { unit, dim, texGen, identity, Matrix4x4f(matrix) }; + m_CommandQueue->WriteValueType<GfxCmdSetTextureTransform>(trans); + GFXDEVICE_LOCKSTEP_CLIENT(); + } + else + m_RealDevice->SetTextureTransform(unit, dim, texGen, identity, matrix); +} + +void GfxDeviceClient::SetTextureName( TextureID texture, char const* name ) +{ + CheckMainThread(); + if (m_Serialize) + { + m_CommandQueue->WriteValueType<GfxCommand>(kGfxCmd_SetTextureName); + GfxCmdSetTextureName texName = { texture, strlen(name)+1 }; + m_CommandQueue->WriteValueType<GfxCmdSetTextureName>(texName); + m_CommandQueue->WriteArrayType<char>(name, strlen(name)+1); + GFXDEVICE_LOCKSTEP_CLIENT(); + } + else + m_RealDevice->SetTextureName( texture, name ); +} + +void GfxDeviceClient::SetMaterialProperties( const MaterialPropertyBlock& block ) +{ + CheckMainThread(); + if (m_Serialize) + { + m_CommandQueue->WriteValueType<GfxCommand>(kGfxCmd_SetMaterialProperties); + int propertyCount = block.GetPropertiesEnd() - block.GetPropertiesBegin(); + int bufferSize = block.GetBufferEnd() - block.GetBufferBegin(); + typedef MaterialPropertyBlock::Property Property; + GfxCmdSetMaterialProperties matprops = { propertyCount, bufferSize }; + m_CommandQueue->WriteValueType<GfxCmdSetMaterialProperties>(matprops); + m_CommandQueue->WriteArrayType<Property>(block.GetPropertiesBegin(), propertyCount); + m_CommandQueue->WriteArrayType<float>(block.GetBufferBegin(), bufferSize); + GFXDEVICE_LOCKSTEP_CLIENT(); + } + else + m_RealDevice->SetMaterialProperties(block); +} + +GpuProgram* GfxDeviceClient::CreateGpuProgram( const std::string& source, CreateGpuProgramOutput& output ) +{ + CheckMainThread(); + DebugAssert(!IsRecording()); + if (m_Serialize) + { + m_CommandQueue->WriteValueType<GfxCommand>(kGfxCmd_CreateGpuProgram); + GpuProgram* result = NULL; + //GfxCmdCreateGpuProgram gpuprog = { parent, source.c_str(), outErrors, &result }; + //m_CommandQueue->WriteValueType<GfxCmdCreateGpuProgram>(gpuprog); + //SubmitCommands(); + //WaitForSignal(); +#if !ENABLE_GFXDEVICE_REMOTE_PROCESS + GfxCmdCreateGpuProgram gpuprog = { source.c_str(), &output, &result }; + m_CommandQueue->WriteValueType<GfxCmdCreateGpuProgram>(gpuprog); + SubmitCommands(); + m_DeviceWorker->WaitForSignal(); +#else + size_t len = source.length(); + m_CommandQueue->WriteValueType<UInt32>(len); + m_CommandQueue->WriteArrayType<char>(source.c_str(), len + 1); + SubmitCommands(); + ReadbackData(m_ReadbackData); + const GfxRet_CreateGpuProgram* returnData = reinterpret_cast<GfxRet_CreateGpuProgram*>(m_ReadbackData.data()); + returnData->GetOutput(output); + result = (GpuProgram*)returnData->gpuProgram; +#endif + UnityMemoryBarrier(); + GFXDEVICE_LOCKSTEP_CLIENT(); + return result; + } + else + return m_RealDevice->CreateGpuProgram(source, output); +} + +void GfxDeviceClient::SetShadersMainThread( ShaderLab::SubProgram* programs[kShaderTypeCount], const ShaderLab::PropertySheet* props ) +{ + CheckMainThread(); + + FogMode fogMode = m_FogParams.mode; + DisplayListContext& context = *m_CurrentContext; + for (int pt = 0; pt < kShaderTypeCount; ++pt) + context.shadersActive[pt] = false; + + // Fill in arrays of GPU programs, parameters and buffer sizes + GfxCmdSetShaders shadersCmd; + for (int pt = 0; pt < kShaderTypeCount; ++pt) + { + if (!programs[pt]) + { + shadersCmd.programs[pt] = NULL; + shadersCmd.params[pt] = NULL; + shadersCmd.paramsBufferSize[pt] = 0; + continue; + } + GpuProgram& gpuProg = programs[pt]->GetGpuProgram(); + GpuProgramParameters& params = programs[pt]->GetParams(fogMode); + shadersCmd.programs[pt] = (ClientIDWrapper(GpuProgram))&gpuProg; +#if !ENABLE_GFXDEVICE_REMOTE_PROCESS_CLIENT + shadersCmd.params[pt] = ¶ms; +#else + if (!params.m_InternalHandle) + { + m_CommandQueue->WriteValueType<GfxCommand>(kGfxCmd_SetGpuProgramParameters); + params.m_InternalHandle = m_GpuProgramParametersMapper.CreateID(); + m_CommandQueue->WriteValueType<ClientIDMapper::ClientID>(params.m_InternalHandle); + dynamic_array<UInt8> outBuf; + dynamic_array<char> strBuf; + Gfx_GpuProgramParameters gfxParams (params, outBuf, strBuf); + m_CommandQueue->WriteValueType<Gfx_GpuProgramParameters>(gfxParams); + + int outSize = outBuf.size(); + m_CommandQueue->WriteValueType<UInt32>(outSize); + m_CommandQueue->WriteValueType<UInt32>(strBuf.size()); + outBuf.resize_uninitialized(outSize + strBuf.size()); + std::copy(strBuf.begin(), strBuf.end(), outBuf.begin()+outSize); + void* buffer = m_CommandQueue->GetWriteDataPointer(outBuf.size(), 1); + memcpy (buffer, outBuf.begin(), outBuf.size()); + } + shadersCmd.params[pt] = params.m_InternalHandle; +#endif + if (!params.IsReady()) + { + CreateShaderParameters (programs[pt], fogMode); + params.MakeReady(); + } + shadersCmd.paramsBufferSize[pt] = params.GetValuesSize(); + ShaderImplType implType = programs[pt]->GetGpuProgram().GetImplType(); + context.shadersActive[pt] = implType == pt; + + // GLSL case, where a single vertex shader SubProgram can encompass multiple stages + if (implType == kShaderImplBoth) + { + context.shadersActive[kShaderVertex] |= true; + context.shadersActive[kShaderFragment] |= true; + } + } + + context.hasSetShaders = true; + + if (m_Serialize) + { + m_CommandQueue->WriteValueType<GfxCommand>(kGfxCmd_SetShaders); + m_CommandQueue->WriteValueType<GfxCmdSetShaders>(shadersCmd); + for (int pt = 0; pt < kShaderTypeCount; ++pt) + { + int bufferSize = shadersCmd.paramsBufferSize[pt]; + if (bufferSize <= 0) + continue; + + void* buffer = m_CommandQueue->GetWriteDataPointer(bufferSize, 1); + UInt8* dest = static_cast<UInt8*>(buffer); + + // Must call GetBuffer() after GetWriteDataPointer() since it might be reallocated! + const UInt8* bufferStart = IsRecording() ? static_cast<const UInt8*>(m_CommandQueue->GetBuffer()) : NULL; + GfxPatchInfo* patchInfo = IsRecording() ? &context.patchInfo : NULL; + programs[pt]->GetParams(fogMode).PrepareValues(props, dest, bufferStart, patchInfo, &context.recordFailed); + } + GFXDEVICE_LOCKSTEP_CLIENT(); + } + else + GraphicsHelper::SetShaders(*m_RealDevice, programs, props); +} + +void GfxDeviceClient::CreateShaderParameters( ShaderLab::SubProgram* program, FogMode fogMode ) +{ + CheckMainThread(); + if (m_Threaded) + { + // Get main command queue even when recording + ThreadedStreamBuffer& stream = m_DisplayListStack[0].commandQueue; + stream.WriteValueType<GfxCommand>(kGfxCmd_CreateShaderParameters); + GfxCmdCreateShaderParameters params = { program, fogMode }; + stream.WriteValueType<GfxCmdCreateShaderParameters>(params); + stream.WriteSubmitData(); + WaitForSignal(); +#if DEBUG_GFXDEVICE_LOCKSTEP + // Lockstep even if recording + GetGfxDeviceWorker()->LockstepWait(); +#endif + } + else + { + m_RealDevice->CreateShaderParameters(program, fogMode); + } +} + +bool GfxDeviceClient::IsShaderActive( ShaderType type ) const +{ + return m_CurrentContext->shadersActive[type]; +} + +void GfxDeviceClient::DestroySubProgram( ShaderLab::SubProgram* subprogram ) +{ + CheckMainThread(); + if (m_Serialize) + { + m_CommandQueue->WriteValueType<GfxCommand>(kGfxCmd_DestroySubProgram); + m_CommandQueue->WriteValueType<ShaderLab::SubProgram*>(subprogram); + GFXDEVICE_LOCKSTEP_CLIENT(); + } + else + m_RealDevice->DestroySubProgram(subprogram); +} + +void GfxDeviceClient::SetConstantBufferInfo (int id, int size) +{ + CheckMainThread(); + if (m_Serialize) + { + m_CommandQueue->WriteValueType<GfxCommand>(kGfxCmd_SetConstantBufferInfo); + m_CommandQueue->WriteValueType<int>(id); + m_CommandQueue->WriteValueType<int>(size); + GFXDEVICE_LOCKSTEP_CLIENT(); + } + else + m_RealDevice->SetConstantBufferInfo (id, size); +} + +void GfxDeviceClient::DisableLights( int startLight ) +{ + CheckMainThread(); + const Vector4f black(0.0F, 0.0F, 0.0F, 0.0F); + for (int i = startLight; i < kMaxSupportedVertexLights; ++i) + { + m_BuiltinParamValues.SetVectorParam(BuiltinShaderVectorParam(kShaderVecLight0Diffuse + i), black); + } + + if (m_Serialize) + { + m_CommandQueue->WriteValueType<GfxCommand>(kGfxCmd_DisableLights); + m_CommandQueue->WriteValueType<int>(startLight); + GFXDEVICE_LOCKSTEP_CLIENT(); + } + else + m_RealDevice->DisableLights(startLight); +} + +void GfxDeviceClient::SetLight( int light, const GfxVertexLight& data) +{ + CheckMainThread(); + DebugAssert(!IsRecording()); + + if (light >= kMaxSupportedVertexLights) + return; + + SetupVertexLightParams (light, data); + + if (m_Serialize) + { + m_CommandQueue->WriteValueType<GfxCommand>(kGfxCmd_SetLight); + m_CommandQueue->WriteValueType<int>(light); + m_CommandQueue->WriteValueType<GfxVertexLight>(data); + GFXDEVICE_LOCKSTEP_CLIENT(); + } + else + m_RealDevice->SetLight(light, data); +} + +void GfxDeviceClient::SetAmbient( const float ambient[4] ) +{ + CheckMainThread(); + m_BuiltinParamValues.SetVectorParam(kShaderVecLightModelAmbient, Vector4f(ambient)); + if (m_Serialize) + { + m_CommandQueue->WriteValueType<GfxCommand>(kGfxCmd_SetAmbient); + m_CommandQueue->WriteValueType<Vector4f>(Vector4f(ambient)); + GFXDEVICE_LOCKSTEP_CLIENT(); + } + else + m_RealDevice->SetAmbient(ambient); +} + +void GfxDeviceClient::RecordEnableFog( FogMode fogMode, const ShaderLab::FloatVal& fogStart, const ShaderLab::FloatVal& fogEnd, const ShaderLab::FloatVal& fogDensity, const ShaderLab::VectorVal& fogColor, const ShaderLab::PropertySheet* props ) +{ + CheckMainThread(); + DebugAssert(IsRecording()); + m_CommandQueue->WriteValueType<GfxCommand>(kGfxCmd_EnableFog); + m_CurrentContext->fogParamsOffset = m_CommandQueue->GetCurrentSize(); + GfxFogParams* fog = m_CommandQueue->GetWritePointer<GfxFogParams>(); + fog->mode = fogMode; + + // Must call GetBuffer() after GetWritePointer() since it might be reallocated! + const void* bufferStart = m_CommandQueue->GetBuffer(); + GfxPatchInfo& patchInfo = m_CurrentContext->patchInfo; + patchInfo.AddPatchableVector(fogColor, fog->color, bufferStart, props); + patchInfo.AddPatchableFloat(fogStart, fog->start, bufferStart, props); + patchInfo.AddPatchableFloat(fogEnd, fog->end, bufferStart, props); + patchInfo.AddPatchableFloat(fogDensity, fog->density, bufferStart, props); + m_FogParams = *fog; + GFXDEVICE_LOCKSTEP_CLIENT(); +} + +void GfxDeviceClient::EnableFog (const GfxFogParams& fog) +{ + CheckMainThread(); + m_FogParams = fog; + if (m_Serialize) + { + m_CommandQueue->WriteValueType<GfxCommand>(kGfxCmd_EnableFog); + if (IsRecording()) + m_CurrentContext->fogParamsOffset = m_CommandQueue->GetCurrentSize(); + m_CommandQueue->WriteValueType<GfxFogParams>(fog); + GFXDEVICE_LOCKSTEP_CLIENT(); + } + else + m_RealDevice->EnableFog(fog); +} + +void GfxDeviceClient::DisableFog() +{ + CheckMainThread(); + m_FogParams.mode = kFogDisabled; + if (m_Serialize) + { + m_CommandQueue->WriteValueType<GfxCommand>(kGfxCmd_DisableFog); + if (IsRecording()) + m_CurrentContext->fogParamsOffset = DisplayListContext::kFogParamsDisable; + GFXDEVICE_LOCKSTEP_CLIENT(); + } + else + m_RealDevice->DisableFog(); +} + +VBO* GfxDeviceClient::CreateVBO() +{ + CheckMainThread(); + Assert(!IsRecording()); + VBO* vbo = new ThreadedVBO(*this); + OnCreateVBO(vbo); + return vbo; +} + +void GfxDeviceClient::DeleteVBO( VBO* vbo ) +{ + CheckMainThread(); + Assert(!IsRecording()); + OnDeleteVBO(vbo); + delete vbo; +} + +DynamicVBO& GfxDeviceClient::GetDynamicVBO() +{ + CheckMainThread(); + if (!m_DynamicVBO) + { + Assert(!m_Threaded); + return m_RealDevice->GetDynamicVBO(); + } + return *m_DynamicVBO; +} + +void GfxDeviceClient::BeginSkinning( int maxSkinCount ) +{ + if (m_Threaded) + { + m_CommandQueue->WriteValueType<GfxCommand>(kGfxCmd_BeginSkinning); + m_CommandQueue->WriteValueType<int>(maxSkinCount); + GFXDEVICE_LOCKSTEP_CLIENT(); + } + // Call this even when threaded + GfxDevice::BeginSkinning(maxSkinCount); +} + +bool GfxDeviceClient::SkinMesh( const SkinMeshInfo& skin, VBO* vbo ) +{ +#if !ENABLE_GFXDEVICE_REMOTE_PROCESS + // Only skin on render thread if buffer is not read back + if (m_Threaded && skin.outVertices == NULL) + { + m_CommandQueue->WriteValueType<GfxCommand>(kGfxCmd_SkinMesh); + m_CommandQueue->WriteValueType<SkinMeshInfo>(skin); + ThreadedVBO* threadedVBO = static_cast<ThreadedVBO*>(vbo); + m_CommandQueue->WriteValueType<ClientDeviceVBO*>(threadedVBO->GetClientDeviceVBO()); + m_CommandQueue->WriteSubmitData(); + GFXDEVICE_LOCKSTEP_CLIENT(); + return true; + } + else +#endif + return GfxDevice::SkinMesh(skin, vbo); +} + +void GfxDeviceClient::EndSkinning() +{ + if (m_Threaded) + { + m_CommandQueue->WriteValueType<GfxCommand>(kGfxCmd_EndSkinning); + GFXDEVICE_LOCKSTEP_CLIENT(); + } + // Call this even when threaded + GfxDevice::EndSkinning(); +} + +#if GFX_ENABLE_DRAW_CALL_BATCHING +void GfxDeviceClient::BeginStaticBatching(const ChannelAssigns& channels, GfxPrimitiveType topology) +{ + if (m_Threaded) + { + m_CommandQueue->WriteValueType<GfxCommand>(kGfxCmd_BeginStaticBatching); + GfxCmdBeginStaticBatching statbat = { channels, topology }; + m_CommandQueue->WriteValueType<GfxCmdBeginStaticBatching>(statbat); + GFXDEVICE_LOCKSTEP_CLIENT(); + } + else + m_RealDevice->BeginStaticBatching(channels, topology); +} + +void GfxDeviceClient::StaticBatchMesh( UInt32 firstVertex, UInt32 vertexCount, const IndexBufferData& indices, UInt32 firstIndexByte, UInt32 indexCount ) +{ + if (m_Threaded) + { + m_CommandQueue->WriteValueType<GfxCommand>(kGfxCmd_StaticBatchMesh); + GfxCmdStaticBatchMesh batch = { firstVertex, vertexCount, indices, firstIndexByte, indexCount }; + m_CommandQueue->WriteValueType<GfxCmdStaticBatchMesh>(batch); + GFXDEVICE_LOCKSTEP_CLIENT(); + } + else + m_RealDevice->StaticBatchMesh(firstVertex, vertexCount, indices, firstIndexByte, indexCount); +} + +void GfxDeviceClient::EndStaticBatching( VBO& vbo, const Matrix4x4f& matrix, TransformType transformType, int sourceChannels ) +{ + if (m_Threaded) + { + m_CommandQueue->WriteValueType<GfxCommand>(kGfxCmd_EndStaticBatching); + ThreadedVBO& threadedVBO = static_cast<ThreadedVBO&>(vbo); + ClientDeviceVBO* clientVBO = threadedVBO.GetClientDeviceVBO(); + GfxCmdEndStaticBatching endbat = { clientVBO, matrix, transformType, sourceChannels }; + m_CommandQueue->WriteValueType<GfxCmdEndStaticBatching>(endbat); + m_CommandQueue->WriteSubmitData(); + GFXDEVICE_LOCKSTEP_CLIENT(); + } + else + m_RealDevice->EndStaticBatching(vbo, matrix, transformType, sourceChannels); +} + +void GfxDeviceClient::BeginDynamicBatching( const ChannelAssigns& shaderChannels, UInt32 channelsInVBO, size_t maxVertices, size_t maxIndices, GfxPrimitiveType topology) +{ + if (m_Threaded) + { + m_CommandQueue->WriteValueType<GfxCommand>(kGfxCmd_BeginDynamicBatching); + GfxCmdBeginDynamicBatching dynbat = { shaderChannels, channelsInVBO, maxVertices, maxIndices, topology }; + m_CommandQueue->WriteValueType<GfxCmdBeginDynamicBatching>(dynbat); + GFXDEVICE_LOCKSTEP_CLIENT(); + } + else + m_RealDevice->BeginDynamicBatching(shaderChannels, channelsInVBO, maxVertices, maxIndices, topology); +} + +void GfxDeviceClient::DynamicBatchMesh( const Matrix4x4f& matrix, const VertexBufferData& vertices, UInt32 firstVertex, UInt32 vertexCount, const IndexBufferData& indices, UInt32 firstIndexByte, UInt32 indexCount ) +{ + if (m_Threaded) + { + m_CommandQueue->WriteValueType<GfxCommand>(kGfxCmd_DynamicBatchMesh); + GfxCmdDynamicBatchMesh batch = { matrix, vertices, firstVertex, vertexCount, indices, firstIndexByte, indexCount }; + m_CommandQueue->WriteValueType<GfxCmdDynamicBatchMesh>(batch); + m_CommandQueue->WriteSubmitData(); + GFXDEVICE_LOCKSTEP_CLIENT(); + } + else + m_RealDevice->DynamicBatchMesh(matrix, vertices, firstVertex, vertexCount, indices, firstIndexByte, indexCount); + +} +#if ENABLE_SPRITES +void GfxDeviceClient::DynamicBatchSprite(const Matrix4x4f* matrix, const SpriteRenderData* rd, ColorRGBA32 color) +{ + if (m_Threaded) + { + m_CommandQueue->WriteValueType<GfxCommand>(kGfxCmd_DynamicBatchSprite); + GfxCmdDynamicBatchSprite batch = { *matrix, rd, color }; + m_CommandQueue->WriteValueType<GfxCmdDynamicBatchSprite>(batch); + m_CommandQueue->WriteSubmitData(); + GFXDEVICE_LOCKSTEP_CLIENT(); + } + else + m_RealDevice->DynamicBatchSprite(matrix, rd, color); +} +#endif +void GfxDeviceClient::EndDynamicBatching( TransformType transformType ) +{ + if (m_Threaded) + { + m_CommandQueue->WriteValueType<GfxCommand>(kGfxCmd_EndDynamicBatching); + GfxCmdEndDynamicBatching endbat = { transformType }; + m_CommandQueue->WriteValueType<GfxCmdEndDynamicBatching>(endbat); + m_CommandQueue->WriteSubmitData(); + GFXDEVICE_LOCKSTEP_CLIENT(); + } + else + m_RealDevice->EndDynamicBatching(transformType); +} +#endif + +void GfxDeviceClient::AddBatchingStats( int batchedTris, int batchedVerts, int batchedCalls ) +{ + if (m_Threaded) + { + m_CommandQueue->WriteValueType<GfxCommand>(kGfxCmd_AddBatchingStats); + GfxCmdAddBatchingStats stats = { batchedTris, batchedVerts, batchedCalls }; + m_CommandQueue->WriteValueType<GfxCmdAddBatchingStats>(stats); + GFXDEVICE_LOCKSTEP_CLIENT(); + } + else + m_RealDevice->AddBatchingStats(batchedTris, batchedVerts, batchedCalls); +} + + +GPUSkinningInfo* GfxDeviceClient::CreateGPUSkinningInfo() +{ + CheckMainThread(); + DebugAssert(!IsRecording()); + SET_ALLOC_OWNER(this); + + // Call create directly. Interface spec says this is safe. + GPUSkinningInfo *realInfo = m_RealDevice->CreateGPUSkinningInfo(); + if(!realInfo) + return NULL; + return new ClientGPUSkinningInfo(realInfo); +} + +void GfxDeviceClient::DeleteGPUSkinningInfo(GPUSkinningInfo *info) +{ + CheckMainThread(); + if (m_Threaded) + { + m_CommandQueue->WriteValueType<GfxCommand>(kGfxCmd_DeleteGPUSkinningInfo); + m_CommandQueue->WriteValueType<GPUSkinningInfo *>(((ClientGPUSkinningInfo *)info)->m_realSkinInfo); + SubmitCommands(); + delete (ClientGPUSkinningInfo *)info; + GFXDEVICE_LOCKSTEP_CLIENT(); +} + else + { + m_RealDevice->DeleteGPUSkinningInfo(((ClientGPUSkinningInfo *)info)->m_realSkinInfo); + delete (ClientGPUSkinningInfo *)info; + } + +} + +void GfxDeviceClient::SkinOnGPU(GPUSkinningInfo * info, bool lastThisFrame) +{ + CheckMainThread(); + if (m_Threaded) + { + ClientGPUSkinningInfo *ci = (ClientGPUSkinningInfo *)info; + + m_CommandQueue->WriteValueType<GfxCommand>(kGfxCmd_SkinOnGPU); + m_CommandQueue->WriteValueType<GPUSkinningInfo *>(ci->m_realSkinInfo); + // Add the vbo object pointer to the stream, ci->m_realSkinInfo->m_destVBO will get updated in the worker. + ThreadedVBO* vbo = (ThreadedVBO*)ci->m_DestVBO; + m_CommandQueue->WriteValueType<ClientDeviceVBO *>(vbo->GetClientDeviceVBO()); + m_CommandQueue->WriteValueType<bool>(lastThisFrame); + SubmitCommands(); + GFXDEVICE_LOCKSTEP_CLIENT(); + } + else + { + ClientGPUSkinningInfo *ci = (ClientGPUSkinningInfo *)info; + ThreadedVBO* vbo = (ThreadedVBO*)ci->m_DestVBO; + ci->m_realSkinInfo->SetDestVBO(vbo->GetNonThreadedVBO()); + m_RealDevice->SkinOnGPU(ci->m_realSkinInfo, lastThisFrame); + } +} + +void GfxDeviceClient::UpdateSkinSourceData(GPUSkinningInfo *info, const void *vertData, const BoneInfluence *skinData, bool dirty) +{ + CheckMainThread(); + if (m_Threaded) + { + m_CommandQueue->WriteValueType<GfxCommand>(kGfxCmd_UpdateSkinSourceData); + m_CommandQueue->WriteValueType<GPUSkinningInfo *>(((ClientGPUSkinningInfo *)info)->m_realSkinInfo); + m_CommandQueue->WriteValueType<const void *>(vertData); + m_CommandQueue->WriteValueType<const BoneInfluence *>(skinData); + m_CommandQueue->WriteValueType<bool>(dirty); + SubmitCommands(); + UInt32 fence = InsertCPUFence(); + WaitOnCPUFence(fence); + GFXDEVICE_LOCKSTEP_CLIENT(); + } + else + { + m_RealDevice->UpdateSkinSourceData(((ClientGPUSkinningInfo *)info)->m_realSkinInfo, vertData, skinData, dirty); + } + +} + +void GfxDeviceClient::UpdateSkinBonePoses(GPUSkinningInfo *info, const int boneCount, const Matrix4x4f* poses) +{ + CheckMainThread(); + if (m_Threaded) + { + m_CommandQueue->WriteValueType<GfxCommand>(kGfxCmd_UpdateSkinBonePoses); + m_CommandQueue->WriteValueType<GPUSkinningInfo *>(((ClientGPUSkinningInfo *)info)->m_realSkinInfo); + m_CommandQueue->WriteValueType<int>(boneCount); + m_CommandQueue->WriteArrayType<Matrix4x4f>(poses, boneCount); + SubmitCommands(); + GFXDEVICE_LOCKSTEP_CLIENT(); + } + else + { + m_RealDevice->UpdateSkinBonePoses(((ClientGPUSkinningInfo *)info)->m_realSkinInfo, boneCount, poses); + } + +} + + + +#if UNITY_XENON +RawVBO* GfxDeviceClient::CreateRawVBO(UInt32 size, UInt32 flags) +{ + CheckMainThread(); + Assert(!IsRecording()); + RawVBO* vbo = new RawThreadedVBO(*this, size, flags); + return vbo; +} + +void GfxDeviceClient::DeleteRawVBO(RawVBO* vbo) +{ + CheckMainThread(); + Assert(!IsRecording()); + delete vbo; +} + + +void GfxDeviceClient::EnablePersistDisplayOnQuit(bool enabled) +{ + CheckMainThread(); + if (m_Serialize) + { + m_CommandQueue->WriteValueType<GfxCommand>(kGfxCmd_EnablePersistDisplayOnQuit); + m_CommandQueue->WriteValueType<bool>(enabled); + SubmitCommands(); + GFXDEVICE_LOCKSTEP_CLIENT(); + } + else + m_RealDevice->EnablePersistDisplayOnQuit(enabled); +} + +void GfxDeviceClient::RegisterTexture2D( TextureID tid, IDirect3DBaseTexture9* texture ) +{ + CheckMainThread(); + if (m_Serialize) + { + m_CommandQueue->WriteValueType<GfxCommand>(kGfxCmd_RegisterTexture2D); + m_CommandQueue->WriteValueType<TextureID>(tid); + m_CommandQueue->WriteValueType<IDirect3DBaseTexture9*>(texture); + SubmitCommands(); + GFXDEVICE_LOCKSTEP_CLIENT(); + } + else + m_RealDevice->RegisterTexture2D(tid, texture); +} + +void GfxDeviceClient::PatchTexture2D( TextureID tid, IDirect3DBaseTexture9* texture ) +{ + CheckMainThread(); + if (m_Serialize) + { + m_CommandQueue->WriteValueType<GfxCommand>(kGfxCmd_PatchTexture2D); + m_CommandQueue->WriteValueType<TextureID>(tid); + m_CommandQueue->WriteValueType<IDirect3DBaseTexture9*>(texture); + SubmitCommands(); + GFXDEVICE_LOCKSTEP_CLIENT(); + } + else + m_RealDevice->PatchTexture2D(tid, texture); +} + +void GfxDeviceClient::DeleteTextureEntryOnly( TextureID textureID ) +{ + CheckMainThread(); + if (m_Serialize) + { + m_CommandQueue->WriteValueType<GfxCommand>(kGfxCmd_DeleteTextureEntryOnly); + m_CommandQueue->WriteValueType<TextureID>(textureID); + SubmitCommands(); + GFXDEVICE_LOCKSTEP_CLIENT(); + } + else + m_RealDevice->DeleteTextureEntryOnly(textureID); +} + +void GfxDeviceClient::UnbindAndDelayReleaseTexture( IDirect3DBaseTexture9* texture ) +{ + CheckMainThread(); + if (m_Serialize) + { + m_CommandQueue->WriteValueType<GfxCommand>(kGfxCmd_UnbindAndDelayReleaseTexture); + m_CommandQueue->WriteValueType<IDirect3DBaseTexture9*>(texture); + SubmitCommands(); + GFXDEVICE_LOCKSTEP_CLIENT(); + } + else + m_RealDevice->UnbindAndDelayReleaseTexture(texture); +} + +void GfxDeviceClient::SetTextureWrapModes( TextureID textureID, TextureWrapMode wrapU, TextureWrapMode wrapV, TextureWrapMode wrapW ) +{ + CheckMainThread(); + if (m_Serialize) + { + m_CommandQueue->WriteValueType<GfxCommand>(kGfxCmd_SetTextureWrapModes); + m_CommandQueue->WriteValueType<TextureID>(textureID); + m_CommandQueue->WriteValueType<TextureWrapMode>(wrapU); + m_CommandQueue->WriteValueType<TextureWrapMode>(wrapV); + m_CommandQueue->WriteValueType<TextureWrapMode>(wrapW); + SubmitCommands(); + GFXDEVICE_LOCKSTEP_CLIENT(); + } + else + m_RealDevice->SetTextureWrapModes(textureID, wrapU, wrapV, wrapW); +} + +void GfxDeviceClient::OnLastFrameCallback() +{ + CheckMainThread(); + if (m_Serialize) + { + m_CommandQueue->WriteValueType<GfxCommand>(kGfxCmd_OnLastFrameCallback); + SubmitCommands(); + GFXDEVICE_LOCKSTEP_CLIENT(); + } + else + m_RealDevice->OnLastFrameCallback(); +} + +xenon::IVideoPlayer* GfxDeviceClient::CreateVideoPlayer(bool fullscreen) +{ + CheckMainThread(); + Assert(!IsRecording()); + xenon::VideoPlayerThreaded* vp = new xenon::VideoPlayerThreaded(*this, fullscreen); + return vp; +} + +void GfxDeviceClient::DeleteVideoPlayer(xenon::IVideoPlayer* player) +{ + CheckMainThread(); + Assert(!IsRecording()); + delete player; +} +#endif + +RenderSurfaceHandle GfxDeviceClient::CreateRenderColorSurface (TextureID textureID, int width, int height, int samples, int depth, TextureDimension dim, RenderTextureFormat format, UInt32 createFlags) +{ + CheckMainThread(); + DebugAssert(!IsRecording()); + ClientDeviceRenderSurface* handle = new ClientDeviceRenderSurface(width, height); + if (m_Serialize) + { + m_CommandQueue->WriteValueType<GfxCommand>(kGfxCmd_CreateRenderColorSurface); + GfxCmdCreateRenderColorSurface create = { textureID, width, height, samples, depth, dim, format, createFlags }; +#if !ENABLE_GFXDEVICE_REMOTE_PROCESS + m_CommandQueue->WriteValueType<ClientDeviceRenderSurface*>(handle); +#else + handle->internalHandle = m_RenderSurfaceMapper.CreateID(); + m_CommandQueue->WriteValueType<ClientDeviceRenderSurface>(*handle); +#endif + m_CommandQueue->WriteValueType<GfxCmdCreateRenderColorSurface>(create); + GFXDEVICE_LOCKSTEP_CLIENT(); + } +#if !ENABLE_GFXDEVICE_REMOTE_PROCESS + else + { + handle->internalHandle = m_RealDevice->CreateRenderColorSurface(textureID, width, height, samples, depth, dim, format, createFlags); + } +#endif + return RenderSurfaceHandle(handle); +} + +RenderSurfaceHandle GfxDeviceClient::CreateRenderDepthSurface (TextureID textureID, int width, int height, int samples, TextureDimension dim, DepthBufferFormat depthFormat, UInt32 createFlags) +{ + CheckMainThread(); + DebugAssert(!IsRecording()); + ClientDeviceRenderSurface* handle = new ClientDeviceRenderSurface(width, height); + handle->zformat = depthFormat; + if (m_Serialize) + { + m_CommandQueue->WriteValueType<GfxCommand>(kGfxCmd_CreateRenderDepthSurface); + GfxCmdCreateRenderDepthSurface create = { textureID, width, height, samples, dim, depthFormat, createFlags }; +#if !ENABLE_GFXDEVICE_REMOTE_PROCESS + m_CommandQueue->WriteValueType<ClientDeviceRenderSurface*>(handle); +#else + handle->internalHandle = m_RenderSurfaceMapper.CreateID(); + m_CommandQueue->WriteValueType<ClientDeviceRenderSurface>(*handle); +#endif + m_CommandQueue->WriteValueType<GfxCmdCreateRenderDepthSurface>(create); + GFXDEVICE_LOCKSTEP_CLIENT(); + } +#if !ENABLE_GFXDEVICE_REMOTE_PROCESS + else + { + handle->internalHandle = m_RealDevice->CreateRenderDepthSurface(textureID, width, height, samples, dim, depthFormat, createFlags); + } +#endif + return RenderSurfaceHandle(handle); +} + +void GfxDeviceClient::DestroyRenderSurface (RenderSurfaceHandle& rs) +{ + CheckMainThread(); + if( !rs.IsValid() ) + return; + + ClientDeviceRenderSurface* handle = static_cast<ClientDeviceRenderSurface*>(rs.object); + if (m_Serialize) + { + m_CommandQueue->WriteValueType<GfxCommand>(kGfxCmd_DestroyRenderSurface); +#if !ENABLE_GFXDEVICE_REMOTE_PROCESS + m_CommandQueue->WriteValueType<ClientDeviceRenderSurface*>(handle); +#else + m_CommandQueue->WriteValueType<ClientDeviceRenderSurface>(*handle); +#endif + GFXDEVICE_LOCKSTEP_CLIENT(); + } +#if !ENABLE_GFXDEVICE_REMOTE_PROCESS + else + { + m_RealDevice->DestroyRenderSurface(handle->internalHandle); + delete handle; + } +#endif + rs.Reset(); +} + +void GfxDeviceClient::DiscardContents (RenderSurfaceHandle& rs) +{ + CheckMainThread(); + if( !rs.IsValid() ) + return; + + ClientDeviceRenderSurface* handle = (ClientDeviceRenderSurface*)rs.object; + handle->state = ClientDeviceRenderSurface::kInitial; // mark as "no contents" + + + if (m_Serialize) + { + m_CommandQueue->WriteValueType<GfxCommand>(kGfxCmd_DiscardContents); +#if !ENABLE_GFXDEVICE_REMOTE_PROCESS + m_CommandQueue->WriteValueType<ClientDeviceRenderSurface*>(handle); +#else + m_CommandQueue->WriteValueType<ClientDeviceRenderSurface>(*handle); +#endif + GFXDEVICE_LOCKSTEP_CLIENT(); + } +#if !ENABLE_GFXDEVICE_REMOTE_PROCESS + else + { + m_RealDevice->DiscardContents(handle->internalHandle); + } +#endif +} + +void GfxDeviceClient::SetRenderTargets (int count, RenderSurfaceHandle* colorHandles, RenderSurfaceHandle depthHandle, int mipLevel, CubemapFace face) +{ + CheckMainThread(); + Assert(!IsRecording()); + + BeforeRenderTargetChange(count, colorHandles, depthHandle); + for (int i = 0; i < count; ++i) + m_ActiveRenderColorSurfaces[i] = colorHandles[i]; + for (int i = count; i < kMaxSupportedRenderTargets; ++i) + m_ActiveRenderColorSurfaces[i].Reset(); + m_ActiveRenderDepthSurface = depthHandle; + AfterRenderTargetChange(); + + if (m_Serialize) + { + m_CommandQueue->WriteValueType<GfxCommand>(kGfxCmd_SetRenderTarget); + GfxCmdSetRenderTarget srt; +#if !ENABLE_GFXDEVICE_REMOTE_PROCESS + for (int i = 0; i < kMaxSupportedRenderTargets; ++i) + srt.colorHandles[i] = m_ActiveRenderColorSurfaces[i]; + srt.depthHandle = depthHandle; +#else + for (int i = 0; i < kMaxSupportedRenderTargets; ++i) + srt.colorHandles[i] = ((ClientDeviceRenderSurface*)(m_ActiveRenderColorSurfaces[i].object))->internalHandle; + srt.depthHandle = ((ClientDeviceRenderSurface*)depthHandle.object)->internalHandle; +#endif + srt.colorCount = count; + srt.face = face; + srt.mipLevel = mipLevel; + m_CommandQueue->WriteValueType<GfxCmdSetRenderTarget>(srt); + SubmitCommands(); + GFXDEVICE_LOCKSTEP_CLIENT(); + } +#if !ENABLE_GFXDEVICE_REMOTE_PROCESS + else + { + RenderSurfaceHandle realColorHandle[kMaxSupportedRenderTargets]; + for (int i = 0; i < count; ++i) + { + ClientDeviceRenderSurface* colorSurf = static_cast<ClientDeviceRenderSurface*>(colorHandles[i].object); + realColorHandle[i].object = colorSurf ? colorSurf->internalHandle.object : NULL; + if(!realColorHandle[i].IsValid()) + realColorHandle[i] = m_RealDevice->GetBackBufferColorSurface(); + } + ClientDeviceRenderSurface* depthSurf = static_cast<ClientDeviceRenderSurface*>(depthHandle.object); + RenderSurfaceHandle realDepthHandle(depthSurf ? depthSurf->internalHandle.object : NULL); + if(!realDepthHandle.IsValid()) + realDepthHandle = m_RealDevice->GetBackBufferDepthSurface(); + + m_RealDevice->SetRenderTargets(count, realColorHandle, realDepthHandle, mipLevel, face); + } +#endif +} + +void GfxDeviceClient::SetRenderTargets (int count, RenderSurfaceHandle* colorHandles, RenderSurfaceHandle depthHandle, int mipLevel, CubemapFace face, UInt32 flags) +{ + CheckMainThread(); + Assert(!IsRecording()); + + BeforeRenderTargetChange(count, colorHandles, depthHandle); + for (int i = 0; i < count; ++i) + m_ActiveRenderColorSurfaces[i] = colorHandles[i]; + for (int i = count; i < kMaxSupportedRenderTargets; ++i) + m_ActiveRenderColorSurfaces[i].Reset(); + m_ActiveRenderDepthSurface = depthHandle; + AfterRenderTargetChange(); + + if (m_Serialize) + { + m_CommandQueue->WriteValueType<GfxCommand>(kGfxCmd_SetRenderTargetWithFlags); + GfxCmdSetRenderTarget srt; +#if !ENABLE_GFXDEVICE_REMOTE_PROCESS + for (int i = 0; i < kMaxSupportedRenderTargets; ++i) + srt.colorHandles[i] = m_ActiveRenderColorSurfaces[i]; + srt.depthHandle = depthHandle; +#else + for (int i = 0; i < kMaxSupportedRenderTargets; ++i) + srt.colorHandles[i] = m_ActiveRenderColorSurfaces[i].object ? ((ClientDeviceRenderSurface*)(m_ActiveRenderColorSurfaces[i].object))->internalHandle : NULL; + srt.depthHandle = depthHandle.object ? ((ClientDeviceRenderSurface*)depthHandle.object)->internalHandle: NULL; +#endif + srt.colorCount = count; + srt.face = face; + srt.mipLevel = mipLevel; + m_CommandQueue->WriteValueType<GfxCmdSetRenderTarget>(srt); + m_CommandQueue->WriteValueType<UInt32>(flags); + SubmitCommands(); + GFXDEVICE_LOCKSTEP_CLIENT(); + } +#if !ENABLE_GFXDEVICE_REMOTE_PROCESS + else + { + RenderSurfaceHandle realColorHandle[kMaxSupportedRenderTargets]; + for (int i = 0; i < count; ++i) + { + ClientDeviceRenderSurface* colorSurf = static_cast<ClientDeviceRenderSurface*>(colorHandles[i].object); + realColorHandle[i].object = colorSurf ? colorSurf->internalHandle.object : NULL; + if(!realColorHandle[i].IsValid()) + realColorHandle[i] = m_RealDevice->GetBackBufferColorSurface(); + } + ClientDeviceRenderSurface* depthSurf = static_cast<ClientDeviceRenderSurface*>(depthHandle.object); + RenderSurfaceHandle realDepthHandle(depthSurf ? depthSurf->internalHandle.object : NULL); + if(!realDepthHandle.IsValid()) + realDepthHandle = m_RealDevice->GetBackBufferDepthSurface(); + + m_RealDevice->SetRenderTargets (count, realColorHandle, realDepthHandle, mipLevel, face, flags); + } +#endif +} + +void GfxDeviceClient::ResolveColorSurface (RenderSurfaceHandle srcHandle, RenderSurfaceHandle dstHandle) +{ + CheckMainThread(); + ClientDeviceRenderSurface* src = static_cast<ClientDeviceRenderSurface*>(srcHandle.object); + ClientDeviceRenderSurface* dst = static_cast<ClientDeviceRenderSurface*>(dstHandle.object); + if (m_Serialize) + { + m_CommandQueue->WriteValueType<GfxCommand>(kGfxCmd_ResolveColorSurface); +#if !ENABLE_GFXDEVICE_REMOTE_PROCESS + m_CommandQueue->WriteValueType<ClientDeviceRenderSurface*>(src); + m_CommandQueue->WriteValueType<ClientDeviceRenderSurface*>(dst); +#else +// m_CommandQueue->WriteValueType<ClientDeviceRenderSurface*>(src.object ? ((ClientDeviceRenderSurface*)(src.object))->internalHandle : NULL); +// m_CommandQueue->WriteValueType<ClientDeviceRenderSurface*>(dst.object ? ((ClientDeviceRenderSurface*)(dst.object))->internalHandle : NULL); + //todo. +#endif + GFXDEVICE_LOCKSTEP_CLIENT(); + } +#if !ENABLE_GFXDEVICE_REMOTE_PROCESS + else + m_RealDevice->ResolveColorSurface (src->internalHandle, dst->internalHandle); +#endif +} + +void GfxDeviceClient::ResolveDepthIntoTexture (RenderSurfaceHandle colorHandle, RenderSurfaceHandle depthHandle) +{ + CheckMainThread(); + if (m_Serialize) + { +#if !ENABLE_GFXDEVICE_REMOTE_PROCESS + GfxCmdResolveDepthIntoTexture resolve = { colorHandle, depthHandle }; +#else + GfxCmdResolveDepthIntoTexture resolve = { colorHandle.object ? ((ClientDeviceRenderSurface*)(colorHandle.object))->internalHandle : NULL , depthHandle.object ? ((ClientDeviceRenderSurface*)(depthHandle.object))->internalHandle : NULL}; +#endif + m_CommandQueue->WriteValueType<GfxCommand>(kGfxCmd_ResolveDepthIntoTexture); + m_CommandQueue->WriteValueType<GfxCmdResolveDepthIntoTexture>(resolve); + GFXDEVICE_LOCKSTEP_CLIENT(); + } +#if !ENABLE_GFXDEVICE_REMOTE_PROCESS + else + { + ClientDeviceRenderSurface* colorSurf = static_cast<ClientDeviceRenderSurface*>(colorHandle.object); + ClientDeviceRenderSurface* depthSurf = static_cast<ClientDeviceRenderSurface*>(depthHandle.object); + m_RealDevice->ResolveDepthIntoTexture (colorSurf->internalHandle, depthSurf->internalHandle); + } +#endif +} + + +RenderSurfaceHandle GfxDeviceClient::GetActiveRenderColorSurface (int index) +{ + CheckMainThread(); + return m_ActiveRenderColorSurfaces[index]; +} + +RenderSurfaceHandle GfxDeviceClient::GetActiveRenderDepthSurface () +{ + CheckMainThread(); + return m_ActiveRenderDepthSurface; +} + +void GfxDeviceClient::BeforeRenderTargetChange(int count, RenderSurfaceHandle* colorHandles, RenderSurfaceHandle depthHandle) +{ + if (!GetFrameStats().m_StatsEnabled) + return; + + // mark any rendered-into render target surfaces as "resolved" + for (int i = 0; i < kMaxSupportedRenderTargets; ++i) + { + if (i >= count || colorHandles[i] != m_ActiveRenderColorSurfaces[i]) + { + ClientDeviceRenderSurface* colorSurf = (ClientDeviceRenderSurface*)m_ActiveRenderColorSurfaces[i].object; + if (colorSurf && colorSurf->state != ClientDeviceRenderSurface::kInitial) + colorSurf->state = ClientDeviceRenderSurface::kResolved; + } + } + + if (depthHandle != m_ActiveRenderDepthSurface) + { + ClientDeviceRenderSurface* depthSurf = (ClientDeviceRenderSurface*)m_ActiveRenderDepthSurface.object; + if (depthSurf && depthSurf->state != ClientDeviceRenderSurface::kInitial) + depthSurf->state = ClientDeviceRenderSurface::kResolved; + } +} + + +void GfxDeviceClient::AfterRenderTargetChange() +{ + if (m_ActiveRenderColorSurfaces[0].IsValid() && !m_ActiveRenderColorSurfaces[0].object->backBuffer) + { + ClientDeviceRenderSurface* colorSurf = (ClientDeviceRenderSurface*)m_ActiveRenderColorSurfaces[0].object; + if (m_ActiveRenderDepthSurface.IsValid()) + { + ClientDeviceRenderSurface* depthSurf = (ClientDeviceRenderSurface*)m_ActiveRenderDepthSurface.object; + if (colorSurf->width != depthSurf->width || colorSurf->height != depthSurf->height) + { + ErrorString("Dimensions of color surface does not match dimensions of depth surface"); + } + } + m_CurrentTargetWidth = colorSurf->width; + m_CurrentTargetHeight = colorSurf->height; + } + else + { +#if UNITY_WINRT + if (0 == m_CurrentWindowWidth && 0 == m_CurrentWindowHeight && NULL != m_RealDevice) + { + m_CurrentTargetWidth = m_RealDevice->GetCurrentTargetWidth(); + m_CurrentTargetHeight = m_RealDevice->GetCurrentTargetHeight(); + m_CurrentWindowWidth = m_CurrentTargetWidth; + m_CurrentWindowHeight = m_CurrentTargetHeight; + } +#endif + m_CurrentTargetWidth = m_CurrentWindowWidth; + m_CurrentTargetHeight = m_CurrentWindowHeight; + } +} + +bool GfxDeviceClient::IsRenderTargetConfigValid(UInt32 width, UInt32 height, RenderTextureFormat colorFormat, DepthBufferFormat depthFormat) +{ + CheckMainThread(); +#if ENABLE_GFXDEVICE_REMOTE_PROCESS_CLIENT + return GfxDevice::IsRenderTargetConfigValid(width, height, colorFormat, depthFormat); +#else + return m_RealDevice->IsRenderTargetConfigValid(width, height, colorFormat, depthFormat); +#endif +} + +void GfxDeviceClient::SetSurfaceFlags(RenderSurfaceHandle surf, UInt32 flags, UInt32 keepFlags) +{ + CheckMainThread(); + if (m_Serialize) + { + m_CommandQueue->WriteValueType<GfxCommand>(kGfxCmd_SetSurfaceFlags); +#if !ENABLE_GFXDEVICE_REMOTE_PROCESS + GfxCmdSetSurfaceFlags sf = { surf, flags, keepFlags }; +#else + GfxCmdSetSurfaceFlags sf = { surf.object ? ((ClientDeviceRenderSurface*)(surf.object))->internalHandle : NULL , flags, keepFlags }; +#endif + m_CommandQueue->WriteValueType<GfxCmdSetSurfaceFlags>(sf); + GFXDEVICE_LOCKSTEP_CLIENT(); + } +#if !ENABLE_GFXDEVICE_REMOTE_PROCESS + else + { + ClientDeviceRenderSurface* surface = (ClientDeviceRenderSurface*)surf.object; + m_RealDevice->SetSurfaceFlags(surface->internalHandle, flags, keepFlags); + } +#endif +} + +void GfxDeviceClient::UploadTexture2D( TextureID texture, TextureDimension dimension, UInt8* srcData, int srcSize, int width, int height, TextureFormat format, int mipCount, UInt32 uploadFlags, int skipMipLevels, TextureUsageMode usageMode, TextureColorSpace colorSpace ) +{ + CheckMainThread(); + if (m_Serialize) + { + // Don't want to upload textures from a display list + m_CurrentContext->recordFailed = true; + m_CommandQueue->WriteValueType<GfxCommand>(kGfxCmd_UploadTexture2D); + Assert(width >= 0 && height >= 0); + GfxCmdUploadTexture2D upload = { texture, dimension, srcSize, width, height, format, mipCount, uploadFlags, skipMipLevels, usageMode, colorSpace }; + m_CommandQueue->WriteValueType<GfxCmdUploadTexture2D>(upload); + WriteBufferData(srcData, srcSize); + GFXDEVICE_LOCKSTEP_CLIENT(); + } + else + m_RealDevice->UploadTexture2D(texture, dimension, srcData, srcSize, width, height, format, mipCount, uploadFlags, skipMipLevels, usageMode, colorSpace); +} + +void GfxDeviceClient::UploadTextureSubData2D( TextureID texture, UInt8* srcData, int srcSize, int mipLevel, int x, int y, int width, int height, TextureFormat format, TextureColorSpace colorSpace ) +{ + CheckMainThread(); + if (m_Serialize) + { + // Don't want to upload textures from a display list + m_CurrentContext->recordFailed = true; + m_CommandQueue->WriteValueType<GfxCommand>(kGfxCmd_UploadTextureSubData2D); + GfxCmdUploadTextureSubData2D upload = { texture, srcSize, mipLevel, x, y, width, height, format, colorSpace }; + m_CommandQueue->WriteValueType<GfxCmdUploadTextureSubData2D>(upload); + WriteBufferData(srcData, srcSize); + GFXDEVICE_LOCKSTEP_CLIENT(); + } + else + m_RealDevice->UploadTextureSubData2D(texture, srcData, srcSize, mipLevel, x, y, width, height, format, colorSpace); +} + +void GfxDeviceClient::UploadTextureCube( TextureID texture, UInt8* srcData, int srcSize, int faceDataSize, int size, TextureFormat format, int mipCount, UInt32 uploadFlags, TextureColorSpace colorSpace ) +{ + CheckMainThread(); + if (m_Serialize) + { + // Don't want to upload textures from a display list + m_CurrentContext->recordFailed = true; + m_CommandQueue->WriteValueType<GfxCommand>(kGfxCmd_UploadTextureCube); + GfxCmdUploadTextureCube upload = { texture, srcSize, faceDataSize, size, format, mipCount, uploadFlags, colorSpace }; + m_CommandQueue->WriteValueType<GfxCmdUploadTextureCube>(upload); + WriteBufferData(srcData, srcSize); + GFXDEVICE_LOCKSTEP_CLIENT(); + } + else + m_RealDevice->UploadTextureCube(texture, srcData, srcSize, faceDataSize, size, format, mipCount, uploadFlags, colorSpace); +} + +void GfxDeviceClient::UploadTexture3D( TextureID texture, UInt8* srcData, int srcSize, int width, int height, int depth, TextureFormat format, int mipCount, UInt32 uploadFlags ) +{ + CheckMainThread(); + if (m_Serialize) + { + // Don't want to upload textures from a display list + m_CurrentContext->recordFailed = true; + m_CommandQueue->WriteValueType<GfxCommand>(kGfxCmd_UploadTexture3D); + GfxCmdUploadTexture3D upload = { texture, srcSize, width, height, depth, format, mipCount, uploadFlags }; + m_CommandQueue->WriteValueType<GfxCmdUploadTexture3D>(upload); + WriteBufferData(srcData, srcSize); + GFXDEVICE_LOCKSTEP_CLIENT(); + } + else + m_RealDevice->UploadTexture3D(texture, srcData, srcSize, width, height, depth, format, mipCount, uploadFlags); +} + +void GfxDeviceClient::DeleteTexture( TextureID texture ) +{ + CheckMainThread(); + if (m_Serialize) + { + m_CommandQueue->WriteValueType<GfxCommand>(kGfxCmd_DeleteTexture); + m_CommandQueue->WriteValueType<TextureID>(texture); + GFXDEVICE_LOCKSTEP_CLIENT(); + } + else + m_RealDevice->DeleteTexture(texture); +} + +GfxDevice::PresentMode GfxDeviceClient::GetPresentMode() +{ + if (!m_Threaded) + { + // If we're not threaded don't change behavior + return m_RealDevice->GetPresentMode(); + } + if (!m_RealDevice) + return kPresentAfterDraw; + GfxDeviceRenderer renderer = m_RealDevice->GetRenderer(); + switch (renderer) + { + case kGfxRendererD3D9: + { + // In D3D9 BeginFrame() waits for the last Present() to finish on the render thread + // so we catch lost device state. It's best to present immediately after drawing. + return kPresentAfterDraw; + } + case kGfxRendererD3D11: + { + // We have to to wait for the last Present() to finish before leaving message loop, + // so it's good to present as early as possible to avoid waiting much (case 488862). + return kPresentBeforeUpdate; + } + default: + { + // By default we synchronize like with D3D9, so the render thread won't fall behind. + return kPresentAfterDraw; + } + } +} + +void GfxDeviceClient::BeginFrame() +{ + CheckMainThread(); + Assert(!m_InsideFrame); + m_InsideFrame = true; + if (m_Serialize) + { + WaitForPendingPresent(); + // Worker thread should check GetNeedsBeginFrame() + m_CommandQueue->WriteValueType<GfxCommand>(kGfxCmd_BeginFrame); + GFXDEVICE_LOCKSTEP_CLIENT(); + } + else + m_RealDevice->BeginFrame(); +} + +void GfxDeviceClient::EndFrame() +{ + CheckMainThread(); + if (!m_InsideFrame) + return; + m_InsideFrame = false; + if (m_Serialize) + { + m_CommandQueue->WriteValueType<GfxCommand>(kGfxCmd_EndFrame); + GFXDEVICE_LOCKSTEP_CLIENT(); + } + else + m_RealDevice->EndFrame(); +} + +void GfxDeviceClient::PresentFrame() +{ + CheckMainThread(); + + ((ClientDeviceRenderSurface*)m_BackBufferColor.object)->state = ClientDeviceRenderSurface::kInitial; + ((ClientDeviceRenderSurface*)m_BackBufferDepth.object)->state = ClientDeviceRenderSurface::kInitial; + + if (m_Serialize) + { + // Check that we waited on event before issuing a new one + bool signalEvent = !m_PresentPending; + m_PresentPending = true; + m_PresentFrameID++; + m_CommandQueue->WriteValueType<GfxCommand>(kGfxCmd_PresentFrame); + m_CommandQueue->WriteValueType<GfxCmdBool>(signalEvent); + m_CommandQueue->WriteValueType<UInt32>(m_PresentFrameID); + SubmitCommands(); + GFXDEVICE_LOCKSTEP_CLIENT(); + } + else + m_RealDevice->PresentFrame(); +} + +bool GfxDeviceClient::IsValidState() +{ + CheckMainThread(); + if (!m_RealDevice) + return true; + return m_RealDevice->IsValidState(); +} + +bool GfxDeviceClient::HandleInvalidState() +{ + CheckMainThread(); + if (IsValidState()) + return true; + Assert(!IsRecording()); + +#if GFX_SUPPORTS_D3D9 + // Mark threaded dynamic VBOs as lost + ResetDynamicVBs(); +#endif +#if GFX_SUPPORTS_OPENGLES20 + // Only mark VBOs lost for GLES2.0 renderers (case 570721) + if (m_Renderer == kGfxRendererOpenGLES20Desktop || m_Renderer == kGfxRendererOpenGLES20Mobile) + MarkAllVBOsLost(); +#endif + + CommonReloadResources(kReleaseRenderTextures); + + bool insideFrame = m_InsideFrame; + if (insideFrame) + EndFrame(); + AcquireThreadOwnership(); + bool success = m_RealDevice->HandleInvalidState(); + ReleaseThreadOwnership(); + if (success && insideFrame) + BeginFrame(); + return success; +} + +void GfxDeviceClient::ResetDynamicResources() +{ + #if GFX_SUPPORTS_D3D9 + // Mark threaded dynamic VBOs as lost + ResetDynamicVBs(); + #endif + + // We should have acquired thread ownership here + Assert(!m_Serialize); + GetRealGfxDevice().ResetDynamicResources(); +} + +bool GfxDeviceClient::IsReadyToBeginFrame() +{ + if (m_Threaded && m_RealDevice->GetRenderer() == kGfxRendererD3D11) + { + // DXGI requires us to keep processing events while the render thread calls Present() + // We have to wait for that before we begin preparing the next frame (case 488862) + return m_DeviceWorker->DidPresentFrame(m_PresentFrameID); + } + return true; +} + +void GfxDeviceClient::FinishRendering() +{ + CheckMainThread(); + if (m_Serialize) + { + m_CommandQueue->WriteValueType<GfxCommand>(kGfxCmd_FinishRendering); + SubmitCommands(); + GetGfxDeviceWorker()->WaitForSignal(); + GFXDEVICE_LOCKSTEP_CLIENT(); + } + else + m_RealDevice->FinishRendering(); +} + +UInt32 GfxDeviceClient::InsertCPUFence() +{ + CheckMainThread(); + if (m_Threaded) + { + m_CommandQueue->WriteValueType<GfxCommand>(kGfxCmd_InsertCPUFence); + SubmitCommands(); + GFXDEVICE_LOCKSTEP_CLIENT(); + return ++m_CurrentCPUFence; + } + return 0; +} + +UInt32 GfxDeviceClient::GetNextCPUFence() +{ + return m_Threaded ? (m_CurrentCPUFence + 1) : 0; +} + +void GfxDeviceClient::WaitOnCPUFence(UInt32 fence) +{ +#if !ENABLE_GFXDEVICE_REMOTE_PROCESS_CLIENT + CheckMainThread(); + if (m_Threaded) + { + // Fence must have been already inserted + if (SInt32(fence - m_CurrentCPUFence) <= 0) + { + m_DeviceWorker->WaitOnCPUFence(fence); + } + else + ErrorString("CPU fence is invalid or very old!"); + } +#endif +} + +void GfxDeviceClient::AcquireThreadOwnership() +{ + CheckMainThread(); + if (!m_Threaded) + return; + + m_ThreadOwnershipCount++; + if (m_ThreadOwnershipCount > 1) + return; + + // Worker releases ownership + Assert(m_Serialize); + m_CommandQueue->WriteValueType<GfxCommand>(kGfxCmd_ReleaseThreadOwnership); + SubmitCommands(); + WaitForSignal(); + GFXDEVICE_LOCKSTEP_CLIENT(); + + // Caller acquires ownership + m_RealDevice->AcquireThreadOwnership(); + + SetRealGfxDeviceThreadOwnership(); + + // We shouldn't serialize any commands + m_Serialize = false; +} + +void GfxDeviceClient::ReleaseThreadOwnership() +{ + CheckMainThread(); + if (!m_Threaded) + return; + + Assert(m_ThreadOwnershipCount); + m_ThreadOwnershipCount--; + if (m_ThreadOwnershipCount > 0) + return; + + // Caller releases ownership + m_RealDevice->ReleaseThreadOwnership(); + + // Worker acquires ownership + m_Serialize = true; + m_CommandQueue->WriteValueType<GfxCommand>(kGfxCmd_AcquireThreadOwnership); + SubmitCommands(); + WaitForSignal(); + GFXDEVICE_LOCKSTEP_CLIENT(); +} + +void GfxDeviceClient::ImmediateVertex( float x, float y, float z ) +{ + CheckMainThread(); + if (m_Serialize) + { + m_CommandQueue->WriteValueType<GfxCommand>(kGfxCmd_ImmediateVertex); + GfxCmdVector3 data = {x, y, z}; + m_CommandQueue->WriteValueType<GfxCmdVector3>(data); + SubmitCommands(); + GFXDEVICE_LOCKSTEP_CLIENT(); + } + else + m_RealDevice->ImmediateVertex(x, y, z); +} + +void GfxDeviceClient::ImmediateNormal( float x, float y, float z ) +{ + CheckMainThread(); + if (m_Serialize) + { + m_CommandQueue->WriteValueType<GfxCommand>(kGfxCmd_ImmediateNormal); + GfxCmdVector3 data = {x, y, z}; + m_CommandQueue->WriteValueType<GfxCmdVector3>(data); + GFXDEVICE_LOCKSTEP_CLIENT(); + } + else + m_RealDevice->ImmediateNormal(x, y, z); +} + +void GfxDeviceClient::ImmediateColor( float r, float g, float b, float a ) +{ + CheckMainThread(); + if (m_Serialize) + { + m_CommandQueue->WriteValueType<GfxCommand>(kGfxCmd_ImmediateColor); + GfxCmdVector4 data = {r, g, b, a}; + m_CommandQueue->WriteValueType<GfxCmdVector4>(data); + GFXDEVICE_LOCKSTEP_CLIENT(); + } + else + m_RealDevice->ImmediateColor(r, g, b, a); +} + +void GfxDeviceClient::ImmediateTexCoordAll( float x, float y, float z ) +{ + CheckMainThread(); + if (m_Serialize) + { + m_CommandQueue->WriteValueType<GfxCommand>(kGfxCmd_ImmediateTexCoordAll); + GfxCmdVector3 data = {x, y, z}; + m_CommandQueue->WriteValueType<GfxCmdVector3>(data); + GFXDEVICE_LOCKSTEP_CLIENT(); + } + else + m_RealDevice->ImmediateTexCoordAll(x, y, z); +} + +void GfxDeviceClient::ImmediateTexCoord( int unit, float x, float y, float z ) +{ + CheckMainThread(); + if (m_Serialize) + { + m_CommandQueue->WriteValueType<GfxCommand>(kGfxCmd_ImmediateTexCoord); + GfxCmdImmediateTexCoord data = {unit, x, y, z}; + m_CommandQueue->WriteValueType<GfxCmdImmediateTexCoord>(data); + GFXDEVICE_LOCKSTEP_CLIENT(); + } + else + m_RealDevice->ImmediateTexCoord(unit, x, y, z); +} + +void GfxDeviceClient::ImmediateBegin( GfxPrimitiveType type ) +{ + CheckMainThread(); + if (m_Serialize) + { + m_CommandQueue->WriteValueType<GfxCommand>(kGfxCmd_ImmediateBegin); + m_CommandQueue->WriteValueType<GfxPrimitiveType>(type); + SubmitCommands(); + GFXDEVICE_LOCKSTEP_CLIENT(); + } + else + m_RealDevice->ImmediateBegin(type); +} + +void GfxDeviceClient::ImmediateEnd() +{ + BeforeDrawCall(true); + CheckMainThread(); + if (m_Serialize) + { + m_CommandQueue->WriteValueType<GfxCommand>(kGfxCmd_ImmediateEnd); + SubmitCommands(); + GFXDEVICE_LOCKSTEP_CLIENT(); + } + else + m_RealDevice->ImmediateEnd(); +} + +bool GfxDeviceClient::BeginRecording() +{ +#if ENABLE_GFXDEVICE_REMOTE_PROCESS + return false; +#endif + Assert(m_RecordDepth < m_MaxCallDepth); + DisplayListContext& parentContext = *m_CurrentContext; + m_RecordDepth++; + m_IsRecording = true; + m_CurrentContext = &m_DisplayListStack[m_RecordDepth]; + memcpy(m_CurrentContext->shadersActive, parentContext.shadersActive, sizeof(parentContext.shadersActive)); + m_CurrentContext->hasSetShaders = false; + m_CommandQueue = &m_CurrentContext->commandQueue; + m_Serialize = true; + return true; +} + +bool GfxDeviceClient::EndRecording( GfxDisplayList** outDisplayList ) +{ + Assert(m_RecordDepth > 0); + m_CommandQueue->WriteValueType<GfxCommand>(kGfxCmd_DisplayList_End); + const void* data = m_CommandQueue->GetBuffer(); + size_t size = m_CommandQueue->GetCurrentSize(); + bool failed = m_CurrentContext->recordFailed; + ThreadedDisplayList* displayList = new ThreadedDisplayList(data, size, *m_CurrentContext); + m_CurrentContext->Reset(); + + m_RecordDepth--; + m_IsRecording = (m_RecordDepth != 0); + m_Serialize = m_Threaded || m_IsRecording; + m_CurrentContext = &m_DisplayListStack[m_RecordDepth]; + m_CommandQueue = &m_CurrentContext->commandQueue; + + // Execute just-recorded display list + displayList->Call(); + + if (failed) + SAFE_RELEASE(displayList); + + Assert(outDisplayList && *outDisplayList==NULL); + *outDisplayList = displayList; + return !failed; +} + +bool GfxDeviceClient::CaptureScreenshot( int left, int bottom, int width, int height, UInt8* rgba32 ) +{ + CheckMainThread(); + if (m_Serialize) + { + bool success = false; + GfxCmdCaptureScreenshot capture = { left, bottom, width, height, rgba32, &success }; + m_CommandQueue->WriteValueType<GfxCommand>(kGfxCmd_CaptureScreenshot); + m_CommandQueue->WriteValueType<GfxCmdCaptureScreenshot>(capture); + SubmitCommands(); + GetGfxDeviceWorker()->WaitForSignal(); + GFXDEVICE_LOCKSTEP_CLIENT(); + return success; + } + else + return m_RealDevice->CaptureScreenshot(left, bottom, width, height, rgba32); +} + +bool GfxDeviceClient::ReadbackImage( ImageReference& image, int left, int bottom, int width, int height, int destX, int destY ) +{ + CheckMainThread(); + if (m_Serialize) + { +#if !ENABLE_GFXDEVICE_REMOTE_PROCESS + bool success = false; + GfxCmdReadbackImage read = { image, left, bottom, width, height, destX, destY, &success }; + m_CommandQueue->WriteValueType<GfxCommand>(kGfxCmd_ReadbackImage); + m_CommandQueue->WriteValueType<GfxCmdReadbackImage>(read); + SubmitCommands(); + GetGfxDeviceWorker()->WaitForSignal(); + GFXDEVICE_LOCKSTEP_CLIENT(); + return success; +#else + // todo. + return false; +#endif + + } + else + return m_RealDevice->ReadbackImage(image, left, bottom, width, height, destX, destY); +} + +void GfxDeviceClient::GrabIntoRenderTexture (RenderSurfaceHandle rs, RenderSurfaceHandle rd, int x, int y, int width, int height) +{ + CheckMainThread(); + if (m_Serialize) + { +#if !ENABLE_GFXDEVICE_REMOTE_PROCESS + GfxCmdGrabIntoRenderTexture grab = { rs, rd, x, y, width, height }; +#else + GfxCmdGrabIntoRenderTexture grab = { rs.object ? ((ClientDeviceRenderSurface*)(rs.object))->internalHandle : NULL , rd.object ? ((ClientDeviceRenderSurface*)(rd.object))->internalHandle : NULL , x, y, width, height }; +#endif + m_CommandQueue->WriteValueType<GfxCommand>(kGfxCmd_GrabIntoRenderTexture); + m_CommandQueue->WriteValueType<GfxCmdGrabIntoRenderTexture>(grab); + SubmitCommands(); + GFXDEVICE_LOCKSTEP_CLIENT(); + } +#if !ENABLE_GFXDEVICE_REMOTE_PROCESS + else + { + ClientDeviceRenderSurface* colorSurf = static_cast<ClientDeviceRenderSurface*>(rs.object); + ClientDeviceRenderSurface* depthSurf = static_cast<ClientDeviceRenderSurface*>(rd.object); + m_RealDevice->GrabIntoRenderTexture(colorSurf->internalHandle, depthSurf->internalHandle, x, y, width, height); + } +#endif +} + + +#if ENABLE_PROFILER +// Gets "what is being done" description from profiler sample +// hierarchy, e.g. "Camera.Render/RenderOpaqueGeometry" +static void GetContextDescriptionFromProfiler(std::string& outName) +{ + UnityProfilerPerThread* profiler = UnityProfilerPerThread::ms_InstanceTLS; + if (profiler) + { + // Do not get the last (most child) level, since that's usually always + // the same like DrawVBO. + for (int level = 3; level > 0; --level) + { + const ProfilerSample* sample = profiler->GetActiveSample(level); + if (sample && sample->information) + { + if (!outName.empty()) + outName += '/'; + outName += sample->information->name; + } + } + } + if (outName.empty()) + outName = "<run with profiler for info>"; +} +#endif // #if ENABLE_PROFILER + + +void GfxDeviceClient::IgnoreNextUnresolveOnCurrentRenderTarget() +{ + for (int i = 0; i < kMaxSupportedRenderTargets; ++i) + { + ClientDeviceRenderSurface* colorSurf = (ClientDeviceRenderSurface*)m_ActiveRenderColorSurfaces[i].object; + if(colorSurf) + colorSurf->state = ClientDeviceRenderSurface::kInitial; + } + + ClientDeviceRenderSurface* depthSurf = (ClientDeviceRenderSurface*)m_ActiveRenderDepthSurface.object; + depthSurf->state = ClientDeviceRenderSurface::kInitial; +} + +void GfxDeviceClient::IgnoreNextUnresolveOnRS(RenderSurfaceHandle rs) +{ + if (!rs.IsValid()) + return; + ((ClientDeviceRenderSurface*)rs.object)->state = ClientDeviceRenderSurface::kInitial; +} + + + +void GfxDeviceClient::BeforeDrawCall(bool immediateMode) +{ + if (!GetFrameStats().m_StatsEnabled) + return; + + ClientDeviceRenderSurface* colorWarn = NULL; + ClientDeviceRenderSurface* depthWarn = NULL; + bool backColorWarn = false; + bool backDepthWarn = false; + + // Check if any of surfaces have been resolved, not cleared/discarded and now + // we want to render into them -- warn about this situation if needed. + // Then set all surfaces as "rendered into". + for (int i = 0; i < kMaxSupportedRenderTargets; ++i) + { + ClientDeviceRenderSurface* colorSurf = (ClientDeviceRenderSurface*)m_ActiveRenderColorSurfaces[i].object; + if(colorSurf) + { + if (colorSurf->state == ClientDeviceRenderSurface::kResolved) + colorWarn = colorSurf; + colorSurf->state = ClientDeviceRenderSurface::kRendered; + } + } + + ClientDeviceRenderSurface* depthSurf = (ClientDeviceRenderSurface*)m_ActiveRenderDepthSurface.object; + if(depthSurf) + { + if (depthSurf->zformat != kDepthFormatNone && depthSurf->state == ClientDeviceRenderSurface::kResolved) + depthWarn = depthSurf; + depthSurf->state = ClientDeviceRenderSurface::kRendered; + } + + #if ENABLE_PROFILER + // In development builds, emit warnings if we're emulating + // a tiled GPU. + if (gGraphicsCaps.warnRenderTargetUnresolves && (colorWarn || depthWarn || backColorWarn || backDepthWarn)) + { + std::string desc; + GetContextDescriptionFromProfiler(desc); + if (colorWarn) + { + WarningStringMsg ("Tiled GPU perf. warning: RenderTexture %s (%dx%d) was not cleared/discarded, doing %s", depthWarn ? "" : "color surface ", colorWarn->width, colorWarn->height, desc.c_str()); + } + else if (depthWarn) + { + WarningStringMsg ("Tiled GPU perf. warning: RenderTexture depth surface (%dx%d) was not cleared/discarded, doing %s", depthWarn->width, depthWarn->height, desc.c_str()); + } + else if (backColorWarn) + { + WarningStringMsg ("Tiled GPU perf. warning: Backbuffer %s was not cleared/discarded, doing %s", backDepthWarn ? "" : "color surface ", desc.c_str()); + } + else if (backDepthWarn) + { + WarningStringMsg ("Tiled GPU perf. warning: Backbuffer depth surface was not cleared/discarded, doing %s", desc.c_str()); + } + } + #endif +} + +bool GfxDeviceClient::IsPositionRequiredForTexGen (int texStageIndex) const +{ +#if GFX_DEVICE_CLIENT_TRACK_TEXGEN + return m_CurrentContext->shadersActive[kShaderVertex] == 0 && (posForTexGen & (1<<texStageIndex) != 0); +#else + return m_RealDevice->IsPositionRequiredForTexGen(texStageIndex); +#endif +} + +bool GfxDeviceClient::IsNormalRequiredForTexGen (int texStageIndex) const +{ +#if GFX_DEVICE_CLIENT_TRACK_TEXGEN + return m_CurrentContext->shadersActive[kShaderVertex] == 0 && (nrmForTexGen & (1<<texStageIndex) != 0); +#else + return m_RealDevice->IsNormalRequiredForTexGen(texStageIndex); +#endif +} + +bool GfxDeviceClient::IsPositionRequiredForTexGen() const +{ +#if GFX_DEVICE_CLIENT_TRACK_TEXGEN + return m_CurrentContext->shadersActive[kShaderVertex] == 0 && posForTexGen != 0; +#else + return m_RealDevice->IsPositionRequiredForTexGen(); +#endif +} + +bool GfxDeviceClient::IsNormalRequiredForTexGen() const +{ +#if GFX_DEVICE_CLIENT_TRACK_TEXGEN + return m_CurrentContext->shadersActive[kShaderVertex] == 0 && nrmForTexGen != 0; +#else + return m_RealDevice->IsNormalRequiredForTexGen(); +#endif +} + +void GfxDeviceClient::SetActiveContext (void* ctx) +{ + CheckMainThread(); + if (m_Serialize) + { + m_CommandQueue->WriteValueType<GfxCommand>(kGfxCmd_SetActiveContext); + m_CommandQueue->WriteValueType<void*>(ctx); + SubmitCommands(); + GetGfxDeviceWorker()->WaitForSignal(); + GFXDEVICE_LOCKSTEP_CLIENT(); + } + else + m_RealDevice->SetActiveContext (ctx); +} + + +void GfxDeviceClient::ResetFrameStats() +{ + CheckMainThread(); + m_Stats.ResetClientStats(); + if (m_Serialize) + { + m_CommandQueue->WriteValueType<GfxCommand>(kGfxCmd_ResetFrameStats); + GFXDEVICE_LOCKSTEP_CLIENT(); + } + else + m_RealDevice->ResetFrameStats(); +} + +void GfxDeviceClient::BeginFrameStats() +{ + ((ClientDeviceRenderSurface*)(m_BackBufferColor.object))->state = ClientDeviceRenderSurface::kInitial; + ((ClientDeviceRenderSurface*)(m_BackBufferDepth.object))->state = ClientDeviceRenderSurface::kInitial; + + CheckMainThread(); + m_Stats.BeginFrameStats(); + if (m_Serialize) + { + m_CommandQueue->ResetWriteWaitTime(); + m_CommandQueue->WriteValueType<GfxCommand>(kGfxCmd_BeginFrameStats); + GFXDEVICE_LOCKSTEP_CLIENT(); + } + else + m_RealDevice->BeginFrameStats(); +} + +void GfxDeviceClient::EndFrameStats() +{ + CheckMainThread(); + m_Stats.EndClientFrameStats(); + if (m_Serialize) + { + m_Stats.m_ClientFrameTime -= m_CommandQueue->GetWriteWaitTime(); + m_CommandQueue->WriteValueType<GfxCommand>(kGfxCmd_EndFrameStats); + GFXDEVICE_LOCKSTEP_CLIENT(); + } + else + m_RealDevice->EndFrameStats(); +} + +void GfxDeviceClient::SaveDrawStats() +{ + CheckMainThread(); + m_SavedStats.CopyClientStats(m_Stats); + if (m_Serialize) + { + m_CommandQueue->WriteValueType<GfxCommand>(kGfxCmd_SaveDrawStats); + GFXDEVICE_LOCKSTEP_CLIENT(); + } + else + m_RealDevice->SaveDrawStats(); +} + +void GfxDeviceClient::RestoreDrawStats() +{ + CheckMainThread(); + m_Stats.CopyClientStats(m_SavedStats); + if (m_Serialize) + { + m_CommandQueue->WriteValueType<GfxCommand>(kGfxCmd_RestoreDrawStats); + GFXDEVICE_LOCKSTEP_CLIENT(); + } + else + m_RealDevice->RestoreDrawStats(); +} + +void GfxDeviceClient::SynchronizeStats() +{ + CheckMainThread(); + if (m_Threaded) + { + GetGfxDeviceWorker()->GetLastFrameStats(m_Stats); + m_CommandQueue->WriteValueType<GfxCommand>(kGfxCmd_SynchronizeStats); + GFXDEVICE_LOCKSTEP_CLIENT(); + } + else + m_Stats.CopyAllDrawStats(m_RealDevice->GetFrameStats()); +} + +void* GfxDeviceClient::GetNativeGfxDevice() +{ + AcquireThreadOwnership (); + void* result = m_RealDevice->GetNativeGfxDevice(); + ReleaseThreadOwnership (); + return result; +} + +void* GfxDeviceClient::GetNativeTexturePointer(TextureID id) +{ + AcquireThreadOwnership (); + void* result = m_RealDevice->GetNativeTexturePointer(id); + ReleaseThreadOwnership (); + return result; +} + +UInt32 GfxDeviceClient::GetNativeTextureID(TextureID id) +{ +#if ENABLE_TEXTUREID_MAP + AcquireThreadOwnership (); + UInt32 result = m_RealDevice->GetNativeTextureID(id); + ReleaseThreadOwnership (); + return result; +#else + return id.m_ID; +#endif +} + +#if ENABLE_TEXTUREID_MAP + intptr_t GfxDeviceClient::CreateExternalTextureFromNative(intptr_t nativeTex) + { + AcquireThreadOwnership (); + intptr_t result = m_RealDevice->CreateExternalTextureFromNative(nativeTex); + ReleaseThreadOwnership (); + return result; + } + void GfxDeviceClient::UpdateExternalTextureFromNative(TextureID tex, intptr_t nativeTex) + { + AcquireThreadOwnership (); + m_RealDevice->UpdateExternalTextureFromNative(tex, nativeTex); + ReleaseThreadOwnership (); + } +#endif + +void GfxDeviceClient::InsertCustomMarker (int marker) +{ + CheckMainThread(); + if (m_Serialize) + { + m_CommandQueue->WriteValueType<GfxCommand>(kGfxCmd_InsertCustomMarker); + m_CommandQueue->WriteValueType<int>(marker); + GFXDEVICE_LOCKSTEP_CLIENT(); + } + else + m_RealDevice->InsertCustomMarker (marker); +} + + +void GfxDeviceClient::SetComputeBufferData (ComputeBufferID bufferHandle, const void* data, size_t size) +{ + CheckMainThread(); + DebugAssert (bufferHandle.IsValid() && data && size); + if (m_Serialize) + { + // Don't want to upload data from a display list + m_CurrentContext->recordFailed = true; + m_CommandQueue->WriteValueType<GfxCommand>(kGfxCmd_SetComputeBufferData); + m_CommandQueue->WriteValueType<ComputeBufferID>(bufferHandle); + m_CommandQueue->WriteValueType<size_t>(size); + m_CommandQueue->WriteStreamingData(data, size); + GFXDEVICE_LOCKSTEP_CLIENT(); + } + else + m_RealDevice->SetComputeBufferData (bufferHandle, data, size); +} + + +void GfxDeviceClient::GetComputeBufferData (ComputeBufferID bufferHandle, void* dest, size_t destSize) +{ + CheckMainThread(); + DebugAssert (bufferHandle.IsValid() && dest && destSize); + if (m_Serialize) + { + m_CommandQueue->WriteValueType<GfxCommand>(kGfxCmd_GetComputeBufferData); + m_CommandQueue->WriteValueType<ComputeBufferID>(bufferHandle); + m_CommandQueue->WriteValueType<size_t>(destSize); + m_CommandQueue->WriteValueType<void*>(dest); + SubmitCommands(); + GetGfxDeviceWorker()->WaitForSignal(); + GFXDEVICE_LOCKSTEP_CLIENT(); + } + else + m_RealDevice->GetComputeBufferData (bufferHandle, dest, destSize); +} + + +void GfxDeviceClient::CopyComputeBufferCount (ComputeBufferID srcBuffer, ComputeBufferID dstBuffer, UInt32 dstOffset) +{ + CheckMainThread(); + if (m_Serialize) + { + m_CommandQueue->WriteValueType<GfxCommand>(kGfxCmd_CopyComputeBufferCount); + m_CommandQueue->WriteValueType<ComputeBufferID>(srcBuffer); + m_CommandQueue->WriteValueType<ComputeBufferID>(dstBuffer); + m_CommandQueue->WriteValueType<UInt32>(dstOffset); + GFXDEVICE_LOCKSTEP_CLIENT(); + } + else + m_RealDevice->CopyComputeBufferCount (srcBuffer, dstBuffer, dstOffset); +} + +void GfxDeviceClient::SetRandomWriteTargetTexture (int index, TextureID tid) +{ + CheckMainThread(); + if (m_Serialize) + { + m_CommandQueue->WriteValueType<GfxCommand>(kGfxCmd_SetRandomWriteTargetTexture); + m_CommandQueue->WriteValueType<int>(index); + m_CommandQueue->WriteValueType<TextureID>(tid); + GFXDEVICE_LOCKSTEP_CLIENT(); + } + else + m_RealDevice->SetRandomWriteTargetTexture (index, tid); +} + +void GfxDeviceClient::SetRandomWriteTargetBuffer (int index, ComputeBufferID bufferHandle) +{ + CheckMainThread(); + if (m_Serialize) + { + m_CommandQueue->WriteValueType<GfxCommand>(kGfxCmd_SetRandomWriteTargetBuffer); + m_CommandQueue->WriteValueType<int>(index); + m_CommandQueue->WriteValueType<ComputeBufferID>(bufferHandle); + GFXDEVICE_LOCKSTEP_CLIENT(); + } + else + m_RealDevice->SetRandomWriteTargetBuffer (index, bufferHandle); +} + +void GfxDeviceClient::ClearRandomWriteTargets () +{ + CheckMainThread(); + if (m_Serialize) + { + m_CommandQueue->WriteValueType<GfxCommand>(kGfxCmd_ClearRandomWriteTargets); + GFXDEVICE_LOCKSTEP_CLIENT(); + } + else + m_RealDevice->ClearRandomWriteTargets (); +} + +ComputeProgramHandle GfxDeviceClient::CreateComputeProgram (const UInt8* code, size_t codeSize) +{ + CheckMainThread(); + DebugAssert(!IsRecording()); + ClientDeviceComputeProgram* handle = UNITY_NEW(ClientDeviceComputeProgram, kMemGfxThread); + if (m_Serialize) + { + // Don't want to upload shaders from a display list + m_CurrentContext->recordFailed = true; + m_CommandQueue->WriteValueType<GfxCommand>(kGfxCmd_CreateComputeProgram); + m_CommandQueue->WriteValueType<ClientDeviceComputeProgram*>(handle); + m_CommandQueue->WriteValueType<size_t>(codeSize); + m_CommandQueue->WriteStreamingData(code, codeSize); + GFXDEVICE_LOCKSTEP_CLIENT(); + } + else + { + handle->internalHandle = m_RealDevice->CreateComputeProgram (code, codeSize); + } + return ComputeProgramHandle(handle); +} + +void GfxDeviceClient::DestroyComputeProgram (ComputeProgramHandle& cpHandle) +{ + CheckMainThread(); + + ClientDeviceComputeProgram* cp = static_cast<ClientDeviceComputeProgram*>(cpHandle.object); + if (!cp) + return; + + if (m_Serialize) + { + m_CommandQueue->WriteValueType<GfxCommand>(kGfxCmd_DestroyComputeProgram); + m_CommandQueue->WriteValueType<ClientDeviceComputeProgram*>(cp); + GFXDEVICE_LOCKSTEP_CLIENT(); + } + else + { + m_RealDevice->DestroyComputeProgram (cp->internalHandle); + UNITY_DELETE (cp, kMemGfxThread); + } + + cpHandle.Reset(); +} + +void GfxDeviceClient::CreateComputeConstantBuffers (unsigned count, const UInt32* sizes, ConstantBufferHandle* outCBs) +{ + Assert (count <= kMaxSupportedConstantBuffers); + + CheckMainThread(); + + for (unsigned i = 0; i < count; ++i) + outCBs[i].object = UNITY_NEW(ClientDeviceConstantBuffer(sizes[i]), kMemGfxThread); + + if (m_Serialize) + { + m_CommandQueue->WriteValueType<GfxCommand>(kGfxCmd_CreateComputeConstantBuffers); + m_CommandQueue->WriteValueType<unsigned>(count); + for (unsigned i = 0; i < count; ++i) + { + ClientDeviceConstantBuffer* handle = static_cast<ClientDeviceConstantBuffer*>(outCBs[i].object); + m_CommandQueue->WriteValueType<ClientDeviceConstantBuffer*>(handle); + } + GFXDEVICE_LOCKSTEP_CLIENT(); + } + else + { + ConstantBufferHandle cbHandles[kMaxSupportedConstantBuffers]; + m_RealDevice->CreateComputeConstantBuffers (count, sizes, cbHandles); + for (unsigned i = 0; i < count; ++i) + { + ClientDeviceConstantBuffer* handle = static_cast<ClientDeviceConstantBuffer*>(outCBs[i].object); + Assert (handle); + handle->internalHandle = cbHandles[i]; + } + } +} + +void GfxDeviceClient::DestroyComputeConstantBuffers (unsigned count, ConstantBufferHandle* cbs) +{ + Assert (count <= kMaxSupportedConstantBuffers); + + CheckMainThread(); + + if (m_Serialize) + { + m_CommandQueue->WriteValueType<GfxCommand>(kGfxCmd_DestroyComputeConstantBuffers); + m_CommandQueue->WriteValueType<unsigned>(count); + for (unsigned i = 0; i < count; ++i) + { + ClientDeviceConstantBuffer* handle = static_cast<ClientDeviceConstantBuffer*>(cbs[i].object); + m_CommandQueue->WriteValueType<ClientDeviceConstantBuffer*>(handle); + } + GFXDEVICE_LOCKSTEP_CLIENT(); + } + else + { + ConstantBufferHandle cbHandles[kMaxSupportedConstantBuffers]; + for (unsigned i = 0; i < count; ++i) + { + ClientDeviceConstantBuffer* handle = static_cast<ClientDeviceConstantBuffer*>(cbs[i].object); + if (handle) + cbHandles[i] = handle->internalHandle; + + UNITY_DELETE (handle, kMemGfxThread); + } + m_RealDevice->DestroyComputeConstantBuffers (count, cbHandles); + } + + for (unsigned i = 0; i < count; ++i) + cbs[i].Reset(); +} + +void GfxDeviceClient::CreateComputeBuffer (ComputeBufferID id, size_t count, size_t stride, UInt32 flags) +{ + CheckMainThread(); + DebugAssert(!IsRecording()); + Assert (id.IsValid()); + if (m_Serialize) + { + m_CommandQueue->WriteValueType<GfxCommand>(kGfxCmd_CreateComputeBuffer); + m_CommandQueue->WriteValueType<ComputeBufferID>(id); + m_CommandQueue->WriteValueType<size_t>(count); + m_CommandQueue->WriteValueType<size_t>(stride); + m_CommandQueue->WriteValueType<UInt32>(flags); + GFXDEVICE_LOCKSTEP_CLIENT(); + } + else + m_RealDevice->CreateComputeBuffer (id, count, stride, flags); +} + +void GfxDeviceClient::DestroyComputeBuffer (ComputeBufferID handle) +{ + if (!handle.IsValid()) + return; + + if (m_Serialize) + { + m_CommandQueue->WriteValueType<GfxCommand>(kGfxCmd_DestroyComputeBuffer); + m_CommandQueue->WriteValueType<ComputeBufferID>(handle); + GFXDEVICE_LOCKSTEP_CLIENT(); + } + else + m_RealDevice->DestroyComputeBuffer (handle); +} + +void GfxDeviceClient::UpdateComputeConstantBuffers (unsigned count, ConstantBufferHandle* cbs, UInt32 cbDirty, size_t dataSize, const UInt8* data, const UInt32* cbSizes, const UInt32* cbOffsets, const int* bindPoints) +{ + CheckMainThread(); + + if (!count) + { + DebugAssert (dataSize == 0); + return; + } + DebugAssert (dataSize != 0); + + if (m_Serialize) + { + m_CommandQueue->WriteValueType<GfxCommand>(kGfxCmd_UpdateComputeConstantBuffers); + m_CommandQueue->WriteValueType<unsigned>(count); + m_CommandQueue->WriteValueType<UInt32>(cbDirty); + for (int i = 0; i < count; ++i) + { + ClientDeviceConstantBuffer* handle = static_cast<ClientDeviceConstantBuffer*>(cbs[i].object); + m_CommandQueue->WriteValueType<ClientDeviceConstantBuffer*>(handle); + m_CommandQueue->WriteValueType<UInt32>(cbSizes[i]); + m_CommandQueue->WriteValueType<UInt32>(cbOffsets[i]); + m_CommandQueue->WriteValueType<int>(bindPoints[i]); + } + m_CommandQueue->WriteValueType<size_t>(dataSize); + m_CommandQueue->WriteStreamingData(data, dataSize); + GFXDEVICE_LOCKSTEP_CLIENT(); + } + else + { + ConstantBufferHandle cbHandles[kMaxSupportedConstantBuffers]; + for (unsigned i = 0; i < count; ++i) + { + ClientDeviceConstantBuffer* handle = static_cast<ClientDeviceConstantBuffer*>(cbs[i].object); + if (handle) + cbHandles[i] = handle->internalHandle; + } + m_RealDevice->UpdateComputeConstantBuffers (count, cbHandles, cbDirty, dataSize, data, cbSizes, cbOffsets, bindPoints); + } +} + +void GfxDeviceClient::UpdateComputeResources ( + unsigned texCount, const TextureID* textures, const int* texBindPoints, + unsigned samplerCount, const unsigned* samplers, + unsigned inBufferCount, const ComputeBufferID* inBuffers, const int* inBufferBindPoints, + unsigned outBufferCount, const ComputeBufferID* outBuffers, const TextureID* outTextures, const UInt32* outBufferBindPoints) +{ + CheckMainThread(); + if (m_Serialize) + { + m_CommandQueue->WriteValueType<GfxCommand>(kGfxCmd_UpdateComputeResources); + m_CommandQueue->WriteValueType<unsigned>(texCount); + for (int i = 0; i < texCount; ++i) + { + m_CommandQueue->WriteValueType<TextureID>(textures[i]); + m_CommandQueue->WriteValueType<int>(texBindPoints[i]); + } + m_CommandQueue->WriteValueType<unsigned>(samplerCount); + for (int i = 0; i < samplerCount; ++i) + { + m_CommandQueue->WriteValueType<unsigned>(samplers[i]); + } + m_CommandQueue->WriteValueType<unsigned>(inBufferCount); + for (int i = 0; i < inBufferCount; ++i) + { + m_CommandQueue->WriteValueType<ComputeBufferID>(inBuffers[i]); + m_CommandQueue->WriteValueType<int>(inBufferBindPoints[i]); + } + m_CommandQueue->WriteValueType<unsigned>(outBufferCount); + for (int i = 0; i < outBufferCount; ++i) + { + m_CommandQueue->WriteValueType<ComputeBufferID>(outBuffers[i]); + m_CommandQueue->WriteValueType<TextureID>(outTextures[i]); + m_CommandQueue->WriteValueType<UInt32>(outBufferBindPoints[i]); + } + GFXDEVICE_LOCKSTEP_CLIENT(); + } + else + m_RealDevice->UpdateComputeResources (texCount, textures, texBindPoints, samplerCount, samplers, inBufferCount, inBuffers, inBufferBindPoints, outBufferCount, outBuffers, outTextures, outBufferBindPoints); +} + +void GfxDeviceClient::DispatchComputeProgram (ComputeProgramHandle cpHandle, unsigned threadsX, unsigned threadsY, unsigned threadsZ) +{ + CheckMainThread(); + + ClientDeviceComputeProgram* cp = static_cast<ClientDeviceComputeProgram*>(cpHandle.object); + if (!cp) + return; + if (m_Serialize) + { + m_CommandQueue->WriteValueType<GfxCommand>(kGfxCmd_DispatchComputeProgram); + m_CommandQueue->WriteValueType<ClientDeviceComputeProgram*>(cp); + m_CommandQueue->WriteValueType<unsigned>(threadsX); + m_CommandQueue->WriteValueType<unsigned>(threadsY); + m_CommandQueue->WriteValueType<unsigned>(threadsZ); + GFXDEVICE_LOCKSTEP_CLIENT(); + } + else + { + m_RealDevice->DispatchComputeProgram (cp->internalHandle, threadsX, threadsY, threadsZ); + } +} + +void GfxDeviceClient::DrawNullGeometry (GfxPrimitiveType topology, int vertexCount, int instanceCount) +{ + CheckMainThread(); + if (m_Serialize) + { + m_CommandQueue->WriteValueType<GfxCommand>(kGfxCmd_DrawNullGeometry); + m_CommandQueue->WriteValueType<GfxPrimitiveType>(topology); + m_CommandQueue->WriteValueType<int>(vertexCount); + m_CommandQueue->WriteValueType<int>(instanceCount); + GFXDEVICE_LOCKSTEP_CLIENT(); + } + else + m_RealDevice->DrawNullGeometry (topology, vertexCount, instanceCount); +} + +void GfxDeviceClient::DrawNullGeometryIndirect (GfxPrimitiveType topology, ComputeBufferID bufferHandle, UInt32 bufferOffset) +{ + CheckMainThread(); + if (m_Serialize) + { + m_CommandQueue->WriteValueType<GfxCommand>(kGfxCmd_DrawNullGeometryIndirect); + m_CommandQueue->WriteValueType<GfxPrimitiveType>(topology); + m_CommandQueue->WriteValueType<ComputeBufferID>(bufferHandle); + m_CommandQueue->WriteValueType<UInt32>(bufferOffset); + GFXDEVICE_LOCKSTEP_CLIENT(); + } + else + m_RealDevice->DrawNullGeometryIndirect (topology, bufferHandle, bufferOffset); +} + + + +#if ENABLE_PROFILER + +void GfxDeviceClient::BeginProfileEvent (const char* name) +{ + CheckMainThread(); + if (m_Serialize) + { + m_CommandQueue->WriteValueType<GfxCommand>(kGfxCmd_BeginProfileEvent); + m_CommandQueue->WriteValueType<const char*>(name); // assuming the pointer doesn't possibly go away! + GFXDEVICE_LOCKSTEP_CLIENT(); + } + else + m_RealDevice->BeginProfileEvent (name); +} +void GfxDeviceClient::EndProfileEvent () +{ + CheckMainThread(); + if (m_Serialize) + { + m_CommandQueue->WriteValueType<GfxCommand>(kGfxCmd_EndProfileEvent); + GFXDEVICE_LOCKSTEP_CLIENT(); + } + else + m_RealDevice->EndProfileEvent (); +} + +void GfxDeviceClient::ProfileControl (GfxProfileControl ctrl, unsigned param) +{ + CheckMainThread(); + if (m_Serialize) + { + m_CommandQueue->WriteValueType<GfxCommand>(kGfxCmd_ProfileControl); + m_CommandQueue->WriteValueType<GfxProfileControl>(ctrl); + m_CommandQueue->WriteValueType<unsigned>(param); + GFXDEVICE_LOCKSTEP_CLIENT(); + } + else + m_RealDevice->ProfileControl (ctrl, param); +} + + +GfxTimerQuery* GfxDeviceClient::CreateTimerQuery() +{ + CheckMainThread(); + Assert(!IsRecording()); + return new ThreadedTimerQuery(*this); +} + +void GfxDeviceClient::DeleteTimerQuery(GfxTimerQuery* query) +{ + CheckMainThread(); + Assert(!IsRecording()); + delete query; +} + +void GfxDeviceClient::BeginTimerQueries() +{ + CheckMainThread(); + if (m_Serialize) + { + m_CommandQueue->WriteValueType<GfxCommand>(kGfxCmd_BeginTimerQueries); + GFXDEVICE_LOCKSTEP_CLIENT(); + } + else + m_RealDevice->BeginTimerQueries(); +} + +void GfxDeviceClient::EndTimerQueries() +{ + CheckMainThread(); + if (m_Serialize) + { + m_CommandQueue->WriteValueType<GfxCommand>(kGfxCmd_EndTimerQueries); + SubmitCommands(); + GFXDEVICE_LOCKSTEP_CLIENT(); + } + else + m_RealDevice->EndTimerQueries(); +} + +#endif + +// Editor-only stuff +#if UNITY_EDITOR + +void GfxDeviceClient::SetAntiAliasFlag( bool aa ) +{ + CheckMainThread(); + if (m_Serialize) + { + m_CommandQueue->WriteValueType<GfxCommand>(kGfxCmd_SetAntiAliasFlag); + m_CommandQueue->WriteValueType<GfxCmdBool>(aa); + GFXDEVICE_LOCKSTEP_CLIENT(); + } + else + m_RealDevice->SetAntiAliasFlag(aa); +} + + +void GfxDeviceClient::DrawUserPrimitives( GfxPrimitiveType type, int vertexCount, UInt32 vertexChannels, const void* data, int stride ) +{ + CheckMainThread(); + if (m_Serialize) + { + m_CommandQueue->WriteValueType<GfxCommand>(kGfxCmd_DrawUserPrimitives); + GfxCmdDrawUserPrimitives user = { type, vertexCount, vertexChannels, stride }; + m_CommandQueue->WriteValueType<GfxCmdDrawUserPrimitives>(user); + m_CommandQueue->WriteStreamingData(data, vertexCount * stride); + GFXDEVICE_LOCKSTEP_CLIENT(); + } + else + m_RealDevice->DrawUserPrimitives(type, vertexCount, vertexChannels, data, stride); +} + +int GfxDeviceClient::GetCurrentTargetAA() const +{ +#if UNITY_WIN + return ThreadedWindow::GetCurrentFSAALevel(); +#else + return 1; // fix this +#endif +} + +#endif + +#if UNITY_EDITOR && UNITY_WIN +//ToDo: This is windows specific code, we should replace HWND window with something more abstract +GfxDeviceWindow* GfxDeviceClient::CreateGfxWindow( HWND window, int width, int height, DepthBufferFormat depthFormat, int antiAlias ) +{ + CheckMainThread(); + ThreadedWindow* result = new ThreadedWindow(window, width, height, depthFormat, antiAlias); + ClientDeviceWindow* handle = result->m_ClientWindow; + if (m_Serialize) + { + m_CommandQueue->WriteValueType<GfxCommand>(kGfxCmd_CreateWindow); + m_CommandQueue->WriteValueType<ClientDeviceWindow*>(handle); + GfxCmdCreateWindow create = { window, width, height, depthFormat, antiAlias }; + m_CommandQueue->WriteValueType<GfxCmdCreateWindow>(create); + SubmitCommands(); + GFXDEVICE_LOCKSTEP_CLIENT(); + } + else + { + handle->internalWindow = m_RealDevice->CreateGfxWindow(window, width, height, depthFormat, antiAlias); + } + + return result; +} + +void GfxDeviceClient::SetActiveWindow(ClientDeviceWindow* handle) +{ + CheckMainThread(); + if (m_Serialize) + { + m_CommandQueue->WriteValueType<GfxCommand>(kGfxCmd_SetActiveWindow); + m_CommandQueue->WriteValueType<ClientDeviceWindow*>(handle); + SubmitCommands(); + GFXDEVICE_LOCKSTEP_CLIENT(); + } + else + handle->GetInternal()->SetAsActiveWindow(); +} + +void GfxDeviceClient::WindowReshape(ClientDeviceWindow* handle, int width, int height, DepthBufferFormat depthFormat, int antiAlias) +{ + CheckMainThread(); + if (m_Serialize) + { + m_CommandQueue->WriteValueType<GfxCommand>(kGfxCmd_WindowReshape); + m_CommandQueue->WriteValueType<ClientDeviceWindow*>(handle); + GfxCmdWindowReshape reshape = { width, height, depthFormat, antiAlias }; + m_CommandQueue->WriteValueType<GfxCmdWindowReshape>(reshape); + SubmitCommands(); + WaitForSignal(); + GFXDEVICE_LOCKSTEP_CLIENT(); + } + else + handle->GetInternal()->Reshape(width, height, depthFormat, antiAlias); +} + +void GfxDeviceClient::WindowDestroy(ClientDeviceWindow* handle) +{ + CheckMainThread(); + if (m_Serialize) + { + m_CommandQueue->WriteValueType<GfxCommand>(kGfxCmd_WindowDestroy); + m_CommandQueue->WriteValueType<ClientDeviceWindow*>(handle); + SubmitCommands(); + WaitForSignal(); + GFXDEVICE_LOCKSTEP_CLIENT(); + } + else + delete handle->GetInternal(); +} + +void GfxDeviceClient::BeginRendering(ClientDeviceWindow* handle) +{ + CheckMainThread(); + m_InsideFrame = true; + if (m_Serialize) + { + WaitForPendingPresent(); + m_CommandQueue->WriteValueType<GfxCommand>(kGfxCmd_BeginRendering); + m_CommandQueue->WriteValueType<ClientDeviceWindow*>(handle); + SubmitCommands(); + GFXDEVICE_LOCKSTEP_CLIENT(); + } + else + handle->GetInternal()->BeginRendering(); +} + +void GfxDeviceClient::EndRendering(ClientDeviceWindow* handle, bool presentContent) +{ + CheckMainThread(); + m_InsideFrame = false; + if (m_Serialize) + { + // Check that we waited on event before issuing a new one + bool signalEvent = !m_PresentPending; + m_PresentPending = true; + m_CommandQueue->WriteValueType<GfxCommand>(kGfxCmd_EndRendering); + m_CommandQueue->WriteValueType<ClientDeviceWindow*>(handle); + m_CommandQueue->WriteValueType<GfxCmdBool>(presentContent); + m_CommandQueue->WriteValueType<GfxCmdBool>(signalEvent); + SubmitCommands(); + GFXDEVICE_LOCKSTEP_CLIENT(); + } + else + handle->GetInternal()->EndRendering(presentContent); +} + +#endif + +#if UNITY_WIN +int GfxDeviceClient::GetCurrentTargetWidth() const +{ + return m_CurrentTargetWidth; +} +int GfxDeviceClient::GetCurrentTargetHeight() const +{ + return m_CurrentTargetHeight; +} + +void GfxDeviceClient::SetCurrentTargetSize(int width, int height) +{ + m_CurrentTargetWidth = width; + m_CurrentTargetHeight = height; +} + +void GfxDeviceClient::SetCurrentWindowSize(int width, int height) +{ + m_CurrentWindowWidth = m_CurrentTargetWidth = width; + m_CurrentWindowHeight = m_CurrentTargetHeight = height; +} +#endif + +void GfxDeviceClient::SetRealGfxDevice(GfxThreadableDevice* realDevice) +{ + if (realDevice) + { + m_RealDevice = realDevice; + m_Renderer = realDevice->GetRenderer(); + m_UsesOpenGLTextureCoords = realDevice->UsesOpenGLTextureCoords(); + m_UsesHalfTexelOffset = realDevice->UsesHalfTexelOffset(); + m_MaxBufferedFrames = realDevice->GetMaxBufferedFrames(); + m_FramebufferDepthFormat = realDevice->GetFramebufferDepthFormat(); +#if UNITY_WIN + m_CurrentTargetWidth = realDevice->GetCurrentTargetWidth(); + m_CurrentTargetHeight = realDevice->GetCurrentTargetHeight(); + m_CurrentWindowWidth = m_CurrentTargetWidth; + m_CurrentWindowHeight = m_CurrentTargetHeight; +#endif + } + else + { + m_RealDevice = NULL; + m_Renderer = kGfxRendererOpenGL; + m_UsesOpenGLTextureCoords = true; + m_UsesHalfTexelOffset = false; + m_MaxBufferedFrames = 1; + } +} + +void GfxDeviceClient::UpdateFogDisabled() +{ + m_FogParams.mode = kFogDisabled; +} + +void GfxDeviceClient::UpdateFogEnabled(const GfxFogParams& fogParams) +{ + m_FogParams = fogParams; +} + +void GfxDeviceClient::UpdateShadersActive(bool shadersActive[kShaderTypeCount]) +{ + memcpy(m_CurrentContext->shadersActive, shadersActive, sizeof(bool[kShaderTypeCount])); +} + +void GfxDeviceClient::CheckMainThread() const +{ + DebugAssert(Thread::CurrentThreadIsMainThread()); +} + +void GfxDeviceClient::WriteBufferData(const void* data, int size) +{ + int maxNonStreamedSize = m_CommandQueue->GetAllocatedSize() / 2; + if (size <= maxNonStreamedSize || IsRecording()) + { + // In the NaCl Web Player, make sure that only complete commands are submitted, as we are not truely + // asynchronous. + #if !ENABLE_GFXDEVICE_REMOTE_PROCESS_CLIENT + SubmitCommands(); + #endif + void* dest = m_CommandQueue->GetWriteDataPointer(size, ThreadedStreamBuffer::kDefaultAlignment); + memcpy(dest, data, size); + SubmitCommands(); + } + else + m_CommandQueue->WriteStreamingData(data, size); +} + +void GfxDeviceClient::ReadbackData(dynamic_array<UInt8>& data, const SInt32 chunkSize) +{ + data.resize_uninitialized(0); + m_CommandQueue->WriteValueType<SInt32>(chunkSize); + for (;;) + { + volatile void* chunkPtr = m_CommandQueue->GetWriteDataPointer(sizeof(SInt32) + chunkSize, ThreadedStreamBuffer::kDefaultAlignment); + volatile SInt32* returnedSizePtr = static_cast<volatile SInt32*>(chunkPtr); + volatile void* returnedDataPtr = &returnedSizePtr[1]; + *returnedSizePtr = -1; + m_CommandQueue->WriteSubmitData(); + while (*returnedSizePtr == -1) + { + WaitForSignal(); + // Busy wait + } + SInt32 size = *returnedSizePtr; + UnityMemoryBarrier(); + if (size > 0 && size <= chunkSize) + { + size_t oldSize = data.size(); + data.resize_uninitialized(oldSize + size); + // Const_cast needed to cast away volatile + memcpy(&data[oldSize], const_cast<const void*>(returnedDataPtr), size); + } + if (size < chunkSize) + break; + } +} + +void GfxDeviceClient::SubmitCommands() +{ + m_CommandQueue->WriteSubmitData(); +} + +void GfxDeviceClient::DoLockstep() +{ + if (!IsRecording()) + { + SubmitCommands(); + GetGfxDeviceWorker()->LockstepWait(); + } +} + +void GfxDeviceClient::WaitForPendingPresent() +{ + if (m_PresentPending) + { + PROFILER_AUTO(gGfxWaitForPresentProf, NULL); + + // We must wait for the last Present() to finish to figure out if device was lost. + // Beginning a new frame on a lost device will cause D3D debug runtime to complain. + // We may also lose any resources we upload on the render thread after seeing D3DERR_DEVICELOST. + m_DeviceWorker->WaitForEvent(GfxDeviceWorker::kEventTypePresent); + m_PresentPending = false; + } +} + +RenderTextureFormat GfxDeviceClient::GetDefaultRTFormat() const +{ +#if ENABLE_GFXDEVICE_REMOTE_PROCESS + return kRTFormatARGB32; +#else + return m_RealDevice->GetDefaultRTFormat(); +#endif +} + +RenderTextureFormat GfxDeviceClient::GetDefaultHDRRTFormat() const +{ +#if ENABLE_GFXDEVICE_REMOTE_PROCESS + return kRTFormatARGBHalf; +#else + return m_RealDevice->GetDefaultHDRRTFormat();; +#endif +} + +#if GFX_DEVICE_CLIENT_TRACK_TEXGEN + void GfxDeviceClient::SetTexGen(int unit, TexGenMode mode) + { + bool posNeeded = (mode == kTexGenObject || mode == kTexGenEyeLinear); + bool nrmNeeded = (mode == kTexGenSphereMap || mode == kTexGenCubeReflect || mode == kTexGenCubeNormal); + + if(posNeeded) posForTexGen |= (1<<unit); + else posForTexGen &= ~(1<<unit); + if(nrmNeeded) nrmForTexGen |= (1<<unit); + else nrmForTexGen &= ~(1<<unit); + } + void GfxDeviceClient::DropTexGen(int unit) + { + posForTexGen &= ~(1<<unit); + nrmForTexGen &= ~(1<<unit); + } +#endif + +#endif //ENABLE_MULTITHREADED_CODE diff --git a/Runtime/GfxDevice/threaded/GfxDeviceClient.h b/Runtime/GfxDevice/threaded/GfxDeviceClient.h new file mode 100644 index 0000000..017fd88 --- /dev/null +++ b/Runtime/GfxDevice/threaded/GfxDeviceClient.h @@ -0,0 +1,423 @@ +#pragma once +#if ENABLE_MULTITHREADED_CODE + +#include "Runtime/GfxDevice/GfxDevice.h" +#include "Runtime/GfxDevice/TransformState.h" +#include "Runtime/GfxDevice/threaded/ClientIDMapper.h" +#include "Runtime/GfxDevice/threaded/ThreadedDeviceStates.h" +#include "Runtime/Utilities/dynamic_array.h" + +class ThreadedStreamBuffer; +class GfxDeviceWorker; +class GfxDeviceWindow; +class ThreadedWindow; +class ThreadedDynamicVBO; +struct DisplayListContext; + +enum +{ + kClientDeviceThreaded = 1 << 0, + kClientDeviceForceRef = 1 << 1, + kClientDeviceUseRealDevice = 1 << 2, + kClientDeviceClientProcess = 1 << 3, + kClientDeviceWorkerProcess = 1 << 4, +}; + +GfxDevice* CreateClientGfxDevice(GfxDeviceRenderer renderer, UInt32 flags, size_t bufferSize = 0, void *buffer=0); +bool GfxDeviceWorkerProcessRunCommand(); + +#define GFX_DEVICE_CLIENT_TRACK_TEXGEN (GFX_SUPPORTS_OPENGLES20 || GFX_SUPPORTS_OPENGLES30) + + +class GfxDeviceClient : public GfxDevice +{ +public: + GfxDeviceClient(bool threaded, bool clientProcess, size_t bufferSize = 0, void *buffer=0); + GFX_API ~GfxDeviceClient(); + + GFX_API void InvalidateState(); + #if GFX_DEVICE_VERIFY_ENABLE + GFX_API void VerifyState(); + #endif + + GFX_API void SetMaxBufferedFrames (int bufferSize); + + GFX_API void Clear (UInt32 clearFlags, const float color[4], float depth, int stencil); + GFX_API void SetUserBackfaceMode( bool enable ); + GFX_API void SetWireframe(bool wire); + GFX_API bool GetWireframe() const; + + GFX_API void SetInvertProjectionMatrix( bool enable ); + GFX_API bool GetInvertProjectionMatrix() const; + + #if GFX_USES_VIEWPORT_OFFSET + GFX_API void SetViewportOffset( float x, float y ); + GFX_API void GetViewportOffset( float &x, float &y ) const; + #endif + + GFX_API GPUSkinningInfo *CreateGPUSkinningInfo(); + GFX_API void DeleteGPUSkinningInfo(GPUSkinningInfo *info); + GFX_API void SkinOnGPU( GPUSkinningInfo * info, bool lastThisFrame ); + GFX_API void UpdateSkinSourceData(GPUSkinningInfo *info, const void *vertData, const BoneInfluence *skinData, bool dirty); + GFX_API void UpdateSkinBonePoses(GPUSkinningInfo *info, const int boneCount, const Matrix4x4f* poses); + + GFX_API DeviceBlendState* CreateBlendState(const GfxBlendState& state); + GFX_API DeviceDepthState* CreateDepthState(const GfxDepthState& state); + GFX_API DeviceStencilState* CreateStencilState(const GfxStencilState& state); + GFX_API DeviceRasterState* CreateRasterState(const GfxRasterState& state); + + GFX_API void RecordSetBlendState(const DeviceBlendState* state, const ShaderLab::FloatVal& alphaRef, const ShaderLab::PropertySheet* props); + GFX_API void SetBlendState(const DeviceBlendState* state, float alphaRef); + GFX_API void SetDepthState(const DeviceDepthState* state); + GFX_API void SetStencilState(const DeviceStencilState* state, int stencilRef); + GFX_API void SetRasterState(const DeviceRasterState* state); + GFX_API void SetSRGBWrite (const bool); + GFX_API bool GetSRGBWrite (); + + #if UNITY_XENON + GFX_API void SetNullPixelShader(); + GFX_API void SetHiZEnable( const HiZstate hiz_enable ); + GFX_API void SetHiStencilState( const bool hiStencilEnable, const bool hiStencilWriteEnable, const int hiStencilRef, const CompareFunction cmpfunc ); + GFX_API void HiStencilFlush( const HiSflush flushtype ); + #endif + + GFX_API void SetWorldMatrix( const float matrix[16] ); + GFX_API void SetViewMatrix( const float matrix[16] ); + GFX_API void SetProjectionMatrix(const Matrix4x4f& matrix); + GFX_API void GetMatrix( float outMatrix[16] ) const; + + GFX_API const float* GetWorldMatrix() const; + GFX_API const float* GetViewMatrix() const; + GFX_API const float* GetProjectionMatrix() const; + GFX_API const float* GetDeviceProjectionMatrix() const; + + GFX_API void SetInverseScale( float invScale ); + + GFX_API void SetNormalizationBackface( NormalizationMode mode, bool backface ); + + GFX_API void SetFFLighting( bool on, bool separateSpecular, ColorMaterialMode colorMaterial ); + GFX_API void RecordSetMaterial( const ShaderLab::VectorVal& ambient, const ShaderLab::VectorVal& diffuse, const ShaderLab::VectorVal& specular, const ShaderLab::VectorVal& emissive, const ShaderLab::FloatVal& shininess, const ShaderLab::PropertySheet* props ); + GFX_API void SetMaterial( const float ambient[4], const float diffuse[4], const float specular[4], const float emissive[4], const float shininess ); + GFX_API void RecordSetColor( const ShaderLab::VectorVal& color, const ShaderLab::PropertySheet* props ); + GFX_API void SetColor( const float color[4] ); + GFX_API void SetViewport( int x, int y, int width, int height ); + GFX_API void GetViewport( int* values ) const; + + GFX_API void SetScissorRect( int x, int y, int width, int height ); + GFX_API void DisableScissor(); + GFX_API bool IsScissorEnabled() const; + GFX_API void GetScissorRect( int values[4] ) const; + + GFX_API TextureCombinersHandle CreateTextureCombiners( int count, const ShaderLab::TextureBinding* texEnvs, const ShaderLab::PropertySheet* props, bool hasVertexColorOrLighting, bool usesAddSpecular ); + GFX_API void DeleteTextureCombiners( TextureCombinersHandle& textureCombiners ); + GFX_API void SetTextureCombiners( TextureCombinersHandle textureCombiners, const ShaderLab::PropertySheet* props ); + + GFX_API void SetTexture (ShaderType shaderType, int unit, int samplerUnit, TextureID texture, TextureDimension dim, float bias); + GFX_API void SetTextureParams( TextureID texture, TextureDimension texDim, TextureFilterMode filter, TextureWrapMode wrap, int anisoLevel, bool hasMipMap, TextureColorSpace colorSpace ); + GFX_API void SetTextureTransform( int unit, TextureDimension dim, TexGenMode texGen, bool identity, const float matrix[16]); + GFX_API void SetTextureName( TextureID texture, char const* name ); + + GFX_API void SetMaterialProperties(const MaterialPropertyBlock& block); + + GFX_API GpuProgram* CreateGpuProgram( const std::string& source, CreateGpuProgramOutput& output ); + GFX_API void SetShadersMainThread( ShaderLab::SubProgram* programs[kShaderTypeCount], const ShaderLab::PropertySheet* props ); + GFX_API bool IsShaderActive( ShaderType type ) const; + GFX_API void DestroySubProgram( ShaderLab::SubProgram* subprogram ); + GFX_API void SetConstantBufferInfo (int id, int size); + + GFX_API void DisableLights( int startLight ); + GFX_API void SetLight( int light, const GfxVertexLight& data); + GFX_API void SetAmbient( const float ambient[4] ); + + GFX_API void RecordEnableFog( FogMode fogMode, const ShaderLab::FloatVal& fogStart, const ShaderLab::FloatVal& fogEnd, const ShaderLab::FloatVal& fogDensity, const ShaderLab::VectorVal& fogColor, const ShaderLab::PropertySheet* props ); + GFX_API void EnableFog( const GfxFogParams& fog ); + GFX_API void DisableFog(); + + GFX_API VBO* CreateVBO(); + GFX_API void DeleteVBO( VBO* vbo ); + GFX_API DynamicVBO& GetDynamicVBO(); + + GFX_API void BeginSkinning( int maxSkinCount ); + GFX_API bool SkinMesh( const SkinMeshInfo& skin, VBO* vbo ); + GFX_API void EndSkinning(); + +#if GFX_ENABLE_DRAW_CALL_BATCHING + GFX_API void BeginStaticBatching(const ChannelAssigns& channels, GfxPrimitiveType topology); + GFX_API void StaticBatchMesh( UInt32 firstVertex, UInt32 vertexCount, const IndexBufferData& indices, UInt32 firstIndexByte, UInt32 indexCount ); + GFX_API void EndStaticBatching( VBO& vbo, const Matrix4x4f& matrix, TransformType transformType, int sourceChannels ); + + GFX_API void BeginDynamicBatching( const ChannelAssigns& shaderChannel, UInt32 channelsInVBO, size_t maxVertices, size_t maxIndices, GfxPrimitiveType topology); + GFX_API void DynamicBatchMesh( const Matrix4x4f& matrix, const VertexBufferData& vertices, UInt32 firstVertex, UInt32 vertexCount, const IndexBufferData& indices, UInt32 firstIndexByte, UInt32 indexCount ); +#if ENABLE_SPRITES + GFX_API void DynamicBatchSprite(const Matrix4x4f* matrix, const SpriteRenderData* rd, ColorRGBA32 color); +#endif + GFX_API void EndDynamicBatching( TransformType transformType ); +#endif + + GFX_API void AddBatchingStats( int batchedTris, int batchedVerts, int batchedCalls ); + +#if UNITY_XENON + GFX_API RawVBO* CreateRawVBO( UInt32 size, UInt32 flags ); + GFX_API void DeleteRawVBO( RawVBO* vbo ); + + GFX_API void EnablePersistDisplayOnQuit( bool enabled ); + GFX_API void OnLastFrameCallback(); + + GFX_API void RegisterTexture2D( TextureID tid, IDirect3DBaseTexture9* texture ); + GFX_API void PatchTexture2D( TextureID tid, IDirect3DBaseTexture9* texture ); + GFX_API void DeleteTextureEntryOnly( TextureID textureID ); + GFX_API void UnbindAndDelayReleaseTexture( IDirect3DBaseTexture9* texture ); + GFX_API void SetTextureWrapModes( TextureID textureID, TextureWrapMode wrapU, TextureWrapMode wrapV, TextureWrapMode wrapW ); + + GFX_API xenon::IVideoPlayer* CreateVideoPlayer(bool fullscreen); + GFX_API void DeleteVideoPlayer(xenon::IVideoPlayer* player); +#endif + + GFX_API RenderSurfaceHandle CreateRenderColorSurface (TextureID textureID, int width, int height, int samples, int depth, TextureDimension dim, RenderTextureFormat format, UInt32 createFlags); + GFX_API RenderSurfaceHandle CreateRenderDepthSurface (TextureID textureID, int width, int height, int samples, TextureDimension dim, DepthBufferFormat depthFormat, UInt32 createFlags); + GFX_API void DestroyRenderSurface (RenderSurfaceHandle& rs); + GFX_API void DiscardContents (RenderSurfaceHandle& rs); + GFX_API void IgnoreNextUnresolveOnCurrentRenderTarget(); + GFX_API void IgnoreNextUnresolveOnRS(RenderSurfaceHandle rs); + GFX_API void SetRenderTargets (int count, RenderSurfaceHandle* colorHandles, RenderSurfaceHandle depthHandle, int mipLevel, CubemapFace face = kCubeFaceUnknown); + GFX_API void SetRenderTargets (int count, RenderSurfaceHandle* colorHandles, RenderSurfaceHandle depthHandle, int mipLevel, CubemapFace face, UInt32 flags); + GFX_API void ResolveColorSurface (RenderSurfaceHandle srcHandle, RenderSurfaceHandle dstHandle); + GFX_API void ResolveDepthIntoTexture (RenderSurfaceHandle colorHandle, RenderSurfaceHandle depthHandle); + + GFX_API RenderSurfaceHandle GetActiveRenderColorSurface (int index); + GFX_API RenderSurfaceHandle GetActiveRenderDepthSurface (); + + GFX_API bool IsRenderTargetConfigValid(UInt32 width, UInt32 height, RenderTextureFormat colorFormat, DepthBufferFormat depthFormat); + + GFX_API void SetSurfaceFlags(RenderSurfaceHandle surf, UInt32 flags, UInt32 keepFlags); + + GFX_API void UploadTexture2D( TextureID texture, TextureDimension dimension, UInt8* srcData, int srcSize, int width, int height, TextureFormat format, int mipCount, UInt32 uploadFlags, int skipMipLevels, TextureUsageMode usageMode, TextureColorSpace colorSpace ); + GFX_API void UploadTextureSubData2D( TextureID texture, UInt8* srcData, int srcSize, int mipLevel, int x, int y, int width, int height, TextureFormat format, TextureColorSpace colorSpace ); + GFX_API void UploadTextureCube( TextureID texture, UInt8* srcData, int srcSize, int faceDataSize, int size, TextureFormat format, int mipCount, UInt32 uploadFlags, TextureColorSpace colorSpace ); + GFX_API void UploadTexture3D( TextureID texture, UInt8* srcData, int srcSize, int width, int height, int depth, TextureFormat format, int mipCount, UInt32 uploadFlags ); + GFX_API void DeleteTexture( TextureID texture ); + + GFX_API PresentMode GetPresentMode(); + + GFX_API void BeginFrame(); + GFX_API void EndFrame(); + GFX_API void PresentFrame(); + GFX_API bool IsValidState(); + GFX_API bool HandleInvalidState(); + GFX_API void ResetDynamicResources(); + GFX_API bool IsReadyToBeginFrame(); + GFX_API void FinishRendering(); + GFX_API UInt32 InsertCPUFence(); + GFX_API UInt32 GetNextCPUFence(); + GFX_API void WaitOnCPUFence(UInt32 fence); + + GFX_API void AcquireThreadOwnership(); + GFX_API void ReleaseThreadOwnership(); + + GFX_API void ImmediateVertex( float x, float y, float z ); + GFX_API void ImmediateNormal( float x, float y, float z ); + GFX_API void ImmediateColor( float r, float g, float b, float a ); + GFX_API void ImmediateTexCoordAll( float x, float y, float z ); + GFX_API void ImmediateTexCoord( int unit, float x, float y, float z ); + GFX_API void ImmediateBegin( GfxPrimitiveType type ); + GFX_API void ImmediateEnd(); + + // Recording display lists + GFX_API bool BeginRecording(); + GFX_API bool EndRecording( GfxDisplayList** outDisplayList ); + + // Capturing screen shots / blits + GFX_API bool CaptureScreenshot( int left, int bottom, int width, int height, UInt8* rgba32 ); + GFX_API bool ReadbackImage( ImageReference& image, int left, int bottom, int width, int height, int destX, int destY ); + GFX_API void GrabIntoRenderTexture (RenderSurfaceHandle rs, RenderSurfaceHandle rd, int x, int y, int width, int height); + + // Any housekeeping around draw calls + GFX_API void BeforeDrawCall( bool immediateMode ); + + GFX_API bool IsPositionRequiredForTexGen (int texStageIndex) const; + GFX_API bool IsNormalRequiredForTexGen (int texStageIndex) const; + GFX_API bool IsPositionRequiredForTexGen() const; + GFX_API bool IsNormalRequiredForTexGen() const; + + GFX_API void SetActiveContext (void* ctx); + + GFX_API void ResetFrameStats(); + GFX_API void BeginFrameStats(); + GFX_API void EndFrameStats(); + GFX_API void SaveDrawStats(); + GFX_API void RestoreDrawStats(); + GFX_API void SynchronizeStats(); + + GFX_API void* GetNativeGfxDevice(); + GFX_API void* GetNativeTexturePointer(TextureID id); + GFX_API UInt32 GetNativeTextureID(TextureID id); +#if ENABLE_TEXTUREID_MAP + GFX_API intptr_t CreateExternalTextureFromNative(intptr_t nativeTex); + GFX_API void UpdateExternalTextureFromNative(TextureID tex, intptr_t nativeTex); +#endif + + GFX_API void InsertCustomMarker (int marker); + + GFX_API void SetComputeBufferData (ComputeBufferID bufferHandle, const void* data, size_t size); + GFX_API void GetComputeBufferData (ComputeBufferID bufferHandle, void* dest, size_t destSize); + GFX_API void CopyComputeBufferCount (ComputeBufferID srcBuffer, ComputeBufferID dstBuffer, UInt32 dstOffset); + + GFX_API void SetRandomWriteTargetTexture (int index, TextureID tid); + GFX_API void SetRandomWriteTargetBuffer (int index, ComputeBufferID bufferHandle); + GFX_API void ClearRandomWriteTargets (); + + GFX_API ComputeProgramHandle CreateComputeProgram (const UInt8* code, size_t codeSize); + GFX_API void DestroyComputeProgram (ComputeProgramHandle& cpHandle); + GFX_API void CreateComputeConstantBuffers (unsigned count, const UInt32* sizes, ConstantBufferHandle* outCBs); + GFX_API void DestroyComputeConstantBuffers (unsigned count, ConstantBufferHandle* cbs); + GFX_API void CreateComputeBuffer (ComputeBufferID id, size_t count, size_t stride, UInt32 flags); + GFX_API void DestroyComputeBuffer (ComputeBufferID handle); + GFX_API void UpdateComputeConstantBuffers (unsigned count, ConstantBufferHandle* cbs, UInt32 cbDirty, size_t dataSize, const UInt8* data, const UInt32* cbSizes, const UInt32* cbOffsets, const int* bindPoints); + GFX_API void UpdateComputeResources ( + unsigned texCount, const TextureID* textures, const int* texBindPoints, + unsigned samplerCount, const unsigned* samplers, + unsigned inBufferCount, const ComputeBufferID* inBuffers, const int* inBufferBindPoints, + unsigned outBufferCount, const ComputeBufferID* outBuffers, const TextureID* outTextures, const UInt32* outBufferBindPoints); + GFX_API void DispatchComputeProgram (ComputeProgramHandle cpHandle, unsigned threadsX, unsigned threadsY, unsigned threadsZ); + + GFX_API void DrawNullGeometry (GfxPrimitiveType topology, int vertexCount, int instanceCount); + GFX_API void DrawNullGeometryIndirect (GfxPrimitiveType topology, ComputeBufferID bufferHandle, UInt32 bufferOffset); + + +#if ENABLE_PROFILER + GFX_API void BeginProfileEvent (const char* name); + GFX_API void EndProfileEvent (); + GFX_API void ProfileControl (GfxProfileControl ctrl, unsigned param); + GFX_API GfxTimerQuery* CreateTimerQuery(); + GFX_API void DeleteTimerQuery(GfxTimerQuery* query); + GFX_API void BeginTimerQueries(); + GFX_API void EndTimerQueries(); +#endif + + // Editor-only stuff +#if UNITY_EDITOR + GFX_API void SetAntiAliasFlag( bool aa ); + GFX_API void DrawUserPrimitives( GfxPrimitiveType type, int vertexCount, UInt32 vertexChannels, const void* data, int stride ); + GFX_API int GetCurrentTargetAA() const; +#endif + +#if UNITY_EDITOR && UNITY_WIN + //ToDo: This is windows specific code, we should replace HWND window with something more abstract + GFX_API GfxDeviceWindow* CreateGfxWindow( HWND window, int width, int height, DepthBufferFormat depthFormat, int antiAlias ); + + void SetActiveWindow(ClientDeviceWindow* handle); + void WindowReshape(ClientDeviceWindow* handle, int width, int height, DepthBufferFormat depthFormat, int antiAlias); + void WindowDestroy(ClientDeviceWindow* handle); + void BeginRendering(ClientDeviceWindow* handle); + void EndRendering(ClientDeviceWindow* handle, bool presentContent); +#endif + +#if UNITY_WIN + GFX_API int GetCurrentTargetWidth() const; + GFX_API int GetCurrentTargetHeight() const; + GFX_API void SetCurrentTargetSize(int width, int height); + GFX_API void SetCurrentWindowSize(int width, int height); +#endif + +#if GFX_OPENGLESxx_ONLY || GFX_SUPPORTS_MOLEHILL + GFX_API void ReloadResources() {}; +#endif + + bool IsThreaded() const { return m_Threaded; } + bool IsSerializing() const { return m_Serialize; } + + ThreadedStreamBuffer* GetCommandQueue() const { return m_CommandQueue; } + GfxDeviceWorker* GetGfxDeviceWorker() const { return m_DeviceWorker; } + + void SetRealGfxDevice(GfxThreadableDevice* realDevice); + void WriteBufferData(const void* data, int size); + void ReadbackData(dynamic_array<UInt8>& data, const SInt32 chunkSize = 16384); + void SubmitCommands(); + void DoLockstep(); + + void QueryGraphicsCaps (); + + GFX_API RenderTextureFormat GetDefaultRTFormat() const; + GFX_API RenderTextureFormat GetDefaultHDRRTFormat() const; + +private: + friend class ThreadedDisplayList; + void UpdateFogDisabled(); + void UpdateFogEnabled(const GfxFogParams& fogParams); + void UpdateShadersActive(bool shadersActive[kShaderTypeCount]); + +private: + void CreateShaderParameters( ShaderLab::SubProgram* program, FogMode fogMode ); + + void CheckMainThread() const; + void BeforeRenderTargetChange(int count, RenderSurfaceHandle* colorHandles, RenderSurfaceHandle depthHandle); + void AfterRenderTargetChange(); + void WaitForPendingPresent(); + void WaitForSignal(); + + typedef std::map< GfxBlendState, ClientDeviceBlendState, memcmp_less<GfxBlendState> > CachedBlendStates; + typedef std::map< GfxDepthState, ClientDeviceDepthState, memcmp_less<GfxDepthState> > CachedDepthStates; + typedef std::map< GfxStencilState, ClientDeviceStencilState, memcmp_less<GfxStencilState> > CachedStencilStates; + typedef std::map< GfxRasterState, ClientDeviceRasterState, memcmp_less<GfxRasterState> > CachedRasterStates; + + GfxDeviceWorker* m_DeviceWorker; + GfxThreadableDevice* m_RealDevice; + bool m_Threaded; + bool m_Serialize; + int m_RecordDepth; + int m_MaxCallDepth; + ThreadedStreamBuffer* m_CommandQueue; + DisplayListContext* m_DisplayListStack; + DisplayListContext* m_CurrentContext; + DynamicVBO* m_DynamicVBO; + bool m_InvertProjectionMatrix; + #if GFX_USES_VIEWPORT_OFFSET + Vector2f m_ViewportOffset; + #endif + CachedBlendStates m_CachedBlendStates; + CachedDepthStates m_CachedDepthStates; + CachedStencilStates m_CachedStencilStates; + CachedRasterStates m_CachedRasterStates; + TransformState m_TransformState; + ClientDeviceRect m_Viewport; + ClientDeviceRect m_ScissorRect; + int m_ScissorEnabled; + RenderSurfaceHandle m_ActiveRenderColorSurfaces[kMaxSupportedRenderTargets]; + RenderSurfaceHandle m_ActiveRenderDepthSurface; + int m_CurrentTargetWidth; + int m_CurrentTargetHeight; + int m_CurrentWindowWidth; + int m_CurrentWindowHeight; + int m_ThreadOwnershipCount; + UInt32 m_CurrentCPUFence; + UInt32 m_PresentFrameID; + bool m_PresentPending; + bool m_Wireframe; + bool m_sRGBWrite; + dynamic_array<UInt8> m_ReadbackData; + +#if GFX_DEVICE_CLIENT_TRACK_TEXGEN + // TEMP: we can actually grab this info from shader, but for now lets just workaround it with minimal impact + // anyway, we should kill ffp (pretty please) + // TODO: it might be needed on more platforms, but for now i care only about gles + UInt8 posForTexGen; + UInt8 nrmForTexGen; + + void SetTexGen(int unit, TexGenMode mode); + void DropTexGen(int unit); +#endif + +public: +#if ENABLE_GFXDEVICE_REMOTE_PROCESS + ClientIDMapper m_BlendStateMapper; + ClientIDMapper m_DepthStateMapper; + ClientIDMapper m_StencilStateMapper; + ClientIDMapper m_RasterStateMapper; + ClientIDMapper m_TextureCombinerMapper; + ClientIDMapper m_VBOMapper; + ClientIDMapper m_RenderSurfaceMapper; + ClientIDMapper m_GpuProgramParametersMapper; +#endif +}; + +#endif diff --git a/Runtime/GfxDevice/threaded/GfxDeviceWorker.cpp b/Runtime/GfxDevice/threaded/GfxDeviceWorker.cpp new file mode 100644 index 0000000..3534e7c --- /dev/null +++ b/Runtime/GfxDevice/threaded/GfxDeviceWorker.cpp @@ -0,0 +1,2161 @@ +#include "UnityPrefix.h" + +#if ENABLE_MULTITHREADED_CODE + +#include "Runtime/GfxDevice/threaded/GfxDeviceWorker.h" +#include "Runtime/GfxDevice/threaded/GfxCommands.h" +#include "Runtime/GfxDevice/threaded/GfxReturnStructs.h" +#include "Runtime/GfxDevice/threaded/ThreadedDeviceStates.h" +#include "Runtime/Threads/ThreadedStreamBuffer.h" +#include "Runtime/Shaders/MaterialProperties.h" +#include "Runtime/Threads/Thread.h" +#include "Runtime/Threads/Semaphore.h" +#include "Runtime/Threads/ThreadUtility.h" +#include "Runtime/GfxDevice/GfxTimerQuery.h" +#include "Runtime/GfxDevice/GfxDeviceSetup.h" +#include "Runtime/GfxDevice/GPUSkinningInfo.h" +#include "Runtime/GfxDevice/threaded/ThreadedWindow.h" +#include "Runtime/GfxDevice/threaded/ThreadedDisplayList.h" +#include "Runtime/Filters/Mesh/MeshSkinning.h" +#include "Runtime/Profiler/Profiler.h" +#include "External/shaderlab/Library/program.h" +#include "External/shaderlab/Library/properties.h" +#include "External/shaderlab/Library/TextureBinding.h" + +#if GFXDEVICE_USE_CACHED_STATE + #define CHECK_CACHED_STATE(x) if (x) + #define SET_CACHED_STATE(dst, src) dst = src; +#else + #define CHECK_CACHED_STATE(x) + #define SET_CACHED_STATE(dst, src) +#endif + +#if UNITY_XENON + #include "PlatformDependent/Xbox360/Source/Services/VideoPlayer.h" + #include "PlatformDependent/Xbox360/Source/GfxDevice/GfxXenonVBO.h" + #include "PlatformDependent/Xbox360/Source/GfxDevice/GfxDeviceXenon.h" + #define GFX_DEVICE_WORKER_PROCESSOR 2 +#else + #define GFX_DEVICE_WORKER_PROCESSOR DEFAULT_UNITY_THREAD_PROCESSOR +#endif + +PROFILER_INFORMATION(gMTDrawProf, "Gfx.Draw", kProfilerRender) +PROFILER_INFORMATION(gMTDrawDynamicProf, "Gfx.DrawDynamic", kProfilerRender) +PROFILER_INFORMATION(gMTDrawStaticBatch, "Gfx.DrawStaticBatch", kProfilerRender) +PROFILER_INFORMATION(gMTDrawDynamicBatch, "Gfx.DrawDynamicBatch", kProfilerRender) + +PROFILER_INFORMATION(gMTSetRT, "Gfx.SetRenderTarget", kProfilerRender) +PROFILER_INFORMATION(gMTPresentFrame, "Gfx.PresentFrame", kProfilerRender) +PROFILER_INFORMATION(gMTBeginQueriesProf, "GPUProfiler.BeginQueries", kProfilerOverhead) +PROFILER_INFORMATION(gMTEndQueriesProf, "GPUProfiler.EndQueries", kProfilerOverhead) + + +#if GFXDEVICE_USE_CACHED_STATE +GfxDeviceWorker::CachedState::CachedState() +{ + normalization = kNormalizationUnknown; + backface = -1; + ambient = Vector4f(-1, -1, -1, -1); + fogEnabled = -1; + fogParams.Invalidate(); +} +#endif + +GfxDeviceWorker::GfxDeviceWorker(int maxCallDepth, ThreadedStreamBuffer* commandQueue) : + m_CallDepth(0), + m_MaxCallDepth(maxCallDepth), + m_WorkerThread(NULL), + m_CommandQueue(commandQueue), + m_MainCommandQueue(commandQueue), + m_CurrentCPUFence(0), + m_PresentFrameID(0), + m_IsThreadOwner(true), + m_Quit(false) +{ + m_FrameStats.ResetFrame(); + m_PlaybackCommandQueues = new ThreadedStreamBuffer[maxCallDepth]; + m_PlaybackDisplayLists = new ThreadedDisplayList*[maxCallDepth]; + memset(m_PlaybackDisplayLists, 0, sizeof(m_PlaybackDisplayLists[0]) * maxCallDepth); + // Event starts signaled so it doesn't block immediately + SignalEvent(kEventTypeTimerQueries); +} + +GfxDeviceWorker::~GfxDeviceWorker() +{ + if (m_WorkerThread) + { + m_WorkerThread->WaitForExit(); + delete m_WorkerThread; + } + SetRealGfxDeviceThreadOwnership(); + DestroyRealGfxDevice(); + delete[] m_PlaybackCommandQueues; + delete[] m_PlaybackDisplayLists; +} + + +GfxThreadableDevice* GfxDeviceWorker::Startup(GfxDeviceRenderer renderer, bool threaded, bool forceRef) +{ +#if !ENABLE_GFXDEVICE_REMOTE_PROCESS_CLIENT + Assert (IsThreadableGfxDevice(renderer)); + + // Create actual device + GfxDevice* dev = CreateRealGfxDevice (renderer, forceRef); + if (!dev) + return NULL; + + m_Device = static_cast<GfxThreadableDevice*>(dev); + SetRealGfxDevice(dev); + + // Create worker thread + if (threaded) + { + m_WorkerThread = new Thread(); + m_WorkerThread->SetName ("UnityGfxDeviceWorker"); + m_Device->ReleaseThreadOwnership(); + m_WorkerThread->Run(GfxDeviceWorker::RunGfxDeviceWorker, this, DEFAULT_UNITY_THREAD_STACK_SIZE, GFX_DEVICE_WORKER_PROCESSOR); + + // In D3D11 we don't want to block on Present(), instead we block on IsReadyToBeginFrame() + if (renderer == kGfxRendererD3D11) + SignalEvent(kEventTypePresent); + } + + return m_Device; +#else + return NULL; +#endif +} + +void GfxDeviceWorker::Signal() +{ +#if !ENABLE_GFXDEVICE_REMOTE_PROCESS + m_WaitSemaphore.Signal(); +#else + UnityMemoryBarrier(); +#endif +} + +void GfxDeviceWorker::WaitForSignal() +{ +#if !ENABLE_GFXDEVICE_REMOTE_PROCESS + m_WaitSemaphore.WaitForSignal(); +#endif +} + +void GfxDeviceWorker::LockstepWait() +{ + m_LockstepSemaphore.WaitForSignal(); +} + +void GfxDeviceWorker::GetLastFrameStats(GfxDeviceStats& stats) +{ + Mutex::AutoLock lock(m_StatsMutex); + stats.CopyAllDrawStats(m_FrameStats); +} + +void GfxDeviceWorker::CallImmediate(ThreadedDisplayList* dlist) +{ + Assert(m_CallDepth == 0); + dlist->AddRef(); + m_PlaybackDisplayLists[m_CallDepth] = dlist; + m_CommandQueue = &m_PlaybackCommandQueues[m_CallDepth]; + m_CommandQueue->CreateReadOnly(dlist->GetData(), dlist->GetSize()); + m_CallDepth++; + while (m_CallDepth > 0) + { + RunCommand(*m_CommandQueue); + } +} + +void GfxDeviceWorker::WaitForEvent(EventType type) +{ +#if !ENABLE_GFXDEVICE_REMOTE_PROCESS + m_EventSemaphores[type].WaitForSignal(); +#endif +} + +void GfxDeviceWorker::SignalEvent(EventType type) +{ +#if !ENABLE_GFXDEVICE_REMOTE_PROCESS + m_EventSemaphores[type].Signal(); +#endif +} + +void GfxDeviceWorker::WaitOnCPUFence(UInt32 fence) +{ + while (SInt32(fence - m_CurrentCPUFence) > 0) + { + Thread::Sleep(0.001); + } +} + +bool GfxDeviceWorker::DidPresentFrame(UInt32 frameID) const +{ + return m_PresentFrameID == frameID; +} + +void* GfxDeviceWorker::RunGfxDeviceWorker(void* data) +{ + #if ENABLE_PROFILER + profiler_initialize_thread ("Render Thread", true); + #endif + + GfxDeviceWorker* worker = (GfxDeviceWorker*) data; + worker->m_Device->AcquireThreadOwnership(); + SetRealGfxDeviceThreadOwnership(); + worker->m_Device->OnDeviceCreated (true); + + worker->Run(); + + #if ENABLE_PROFILER + profiler_cleanup_thread(); + #endif + + return NULL; +} + +// Soft-toggle for spin-loop +bool g_enableGfxDeviceWorkerSpinLoop = false; + +GfxCommand lastCmd; +void GfxDeviceWorker::Run() +{ + +#define SPIN_WORKER_LOOP UNITY_XENON +#if SPIN_WORKER_LOOP + while (!m_Quit) + { + if (g_enableGfxDeviceWorkerSpinLoop == false || m_CommandQueue->HasDataToRead()) + { + RunCommand(*m_CommandQueue); + } + else + { + const bool presented = IsRealGfxDeviceThreadOwner() ? GetGfxDeviceX360().PresentFrameForTCR022() : false; + if (!presented) + Thread::Sleep(0.001); + } + } +#else + while (!m_Quit) + { + RunCommand(*m_CommandQueue); + } +#endif +} + +bool GfxDeviceWorker::RunCommandIfDataIsAvailable() +{ + if (!m_CommandQueue->HasData()) + return false; + + RunCommand(*m_CommandQueue); + return true; +} + +void GfxDeviceWorker::RunCommand(ThreadedStreamBuffer& stream) +{ +#if DEBUG_GFXDEVICE_LOCKSTEP + size_t pos = stream.GetDebugReadPosition(); +#endif + GfxCommand cmd = stream.ReadValueType<GfxCommand>(); + DebugAssert(m_IsThreadOwner || cmd == kGfxCmd_AcquireThreadOwnership); + switch (cmd) + { + case kGfxCmd_InvalidateState: + { + m_Device->InvalidateState(); + break; + } +#if GFX_DEVICE_VERIFY_ENABLE + case kGfxCmd_VerifyState: + { + m_Device->VerifyState(); + break; + } +#endif + case kGfxCmd_SetMaxBufferedFrames: + { + int bufferSize = stream.ReadValueType<int>(); + m_Device->SetMaxBufferedFrames(bufferSize); + break; + } + case kGfxCmd_Clear: + { + const GfxCmdClear& clear = stream.ReadValueType<GfxCmdClear>(); + m_Device->Clear(clear.clearFlags, clear.color.GetPtr(), clear.depth, clear.stencil); + stream.ReadReleaseData(); + break; + } + case kGfxCmd_SetUserBackfaceMode: + { + bool enable = stream.ReadValueType<GfxCmdBool>(); + m_Device->SetUserBackfaceMode(enable); + break; + } + case kGfxCmd_SetWireframe: + { + bool wire = stream.ReadValueType<GfxCmdBool>(); + m_Device->SetWireframe(wire); + break; + } + case kGfxCmd_SetInvertProjectionMatrix: + { + bool enable = stream.ReadValueType<GfxCmdBool>(); + m_Device->SetInvertProjectionMatrix(enable); + break; + } +#if GFX_USES_VIEWPORT_OFFSET + case kGfxCmd_SetViewportOffset: + { + Vector2f ofs = stream.ReadValueType<Vector2f>(); + m_Device->SetViewportOffset(ofs.x, ofs.y); + break; + } +#endif + case kGfxCmd_CreateBlendState: + { +#if ENABLE_GFXDEVICE_REMOTE_PROCESS + ClientDeviceBlendState result = stream.ReadValueType<ClientDeviceBlendState>(); + m_BlendStateMapper[result.internalState] = m_Device->CreateBlendState(result.sourceState); +#else + ClientDeviceBlendState* result = stream.ReadValueType<ClientDeviceBlendState*>(); + result->internalState = m_Device->CreateBlendState(result->sourceState); +#endif + stream.ReadReleaseData(); + break; + } + case kGfxCmd_CreateDepthState: + { +#if ENABLE_GFXDEVICE_REMOTE_PROCESS + ClientDeviceDepthState result = stream.ReadValueType<ClientDeviceDepthState>(); + m_DepthStateMapper[result.internalState] = m_Device->CreateDepthState(result.sourceState); +#else + ClientDeviceDepthState* result = stream.ReadValueType<ClientDeviceDepthState*>(); + result->internalState = m_Device->CreateDepthState(result->sourceState); +#endif + stream.ReadReleaseData(); + break; + } + case kGfxCmd_CreateStencilState: + { +#if ENABLE_GFXDEVICE_REMOTE_PROCESS + ClientDeviceStencilState result = stream.ReadValueType<ClientDeviceStencilState>(); + m_StencilStateMapper[result.internalState] = m_Device->CreateStencilState(result.sourceState); +#else + ClientDeviceStencilState* result = stream.ReadValueType<ClientDeviceStencilState*>(); + result->internalState = m_Device->CreateStencilState(result->sourceState); +#endif + stream.ReadReleaseData(); + break; + } + case kGfxCmd_CreateRasterState: + { +#if ENABLE_GFXDEVICE_REMOTE_PROCESS + ClientDeviceRasterState result = stream.ReadValueType<ClientDeviceRasterState>(); + m_RasterStateMapper[result.internalState] = m_Device->CreateRasterState(result.sourceState); +#else + ClientDeviceRasterState* result = stream.ReadValueType<ClientDeviceRasterState*>(); + result->internalState = m_Device->CreateRasterState(result->sourceState); +#endif + stream.ReadReleaseData(); + break; + } + case kGfxCmd_SetBlendState: + { +#if ENABLE_GFXDEVICE_REMOTE_PROCESS + const ClientDeviceBlendState result = stream.ReadValueType<const ClientDeviceBlendState>(); + float alphaRef = stream.ReadValueType<float>(); + m_Device->SetBlendState(m_BlendStateMapper[result.internalState], alphaRef); +#else + const ClientDeviceBlendState* result = stream.ReadValueType<const ClientDeviceBlendState*>(); + float alphaRef = stream.ReadValueType<float>(); + m_Device->SetBlendState(result->internalState, alphaRef); +#endif + break; + } + case kGfxCmd_SetDepthState: + { +#if ENABLE_GFXDEVICE_REMOTE_PROCESS + const ClientDeviceDepthState result = stream.ReadValueType<const ClientDeviceDepthState>(); + m_Device->SetDepthState(m_DepthStateMapper[result.internalState]); +#else + const ClientDeviceDepthState* result = stream.ReadValueType<const ClientDeviceDepthState*>(); + m_Device->SetDepthState(result->internalState); +#endif + break; + } + case kGfxCmd_SetStencilState: + { +#if ENABLE_GFXDEVICE_REMOTE_PROCESS + const ClientDeviceStencilState result = stream.ReadValueType<const ClientDeviceStencilState>(); + int stencilRef = stream.ReadValueType<int>(); + m_Device->SetStencilState(m_StencilStateMapper[result.internalState], stencilRef); +#else + const ClientDeviceStencilState* result = stream.ReadValueType<const ClientDeviceStencilState*>(); + int stencilRef = stream.ReadValueType<int>(); + m_Device->SetStencilState(result->internalState, stencilRef); +#endif + break; + } + case kGfxCmd_SetRasterState: + { +#if ENABLE_GFXDEVICE_REMOTE_PROCESS + const ClientDeviceRasterState result = stream.ReadValueType<const ClientDeviceRasterState>(); + m_Device->SetRasterState(m_RasterStateMapper[result.internalState]); +#else + const ClientDeviceRasterState* result = stream.ReadValueType<const ClientDeviceRasterState*>(); + m_Device->SetRasterState(result->internalState); +#endif + break; + } + case kGfxCmd_SetSRGBState: + { + bool enable = stream.ReadValueType<GfxCmdBool>(); + m_Device->SetSRGBWrite(enable); + break; + } + case kGfxCmd_SetWorldMatrix: + { + const Matrix4x4f& matrix = stream.ReadValueType<Matrix4x4f>(); + m_Device->SetWorldMatrix(matrix.GetPtr()); + break; + } + case kGfxCmd_SetViewMatrix: + { + const Matrix4x4f& matrix = stream.ReadValueType<Matrix4x4f>(); + m_Device->SetViewMatrix(matrix.GetPtr()); + break; + } + case kGfxCmd_SetProjectionMatrix: + { + const Matrix4x4f& matrix = stream.ReadValueType<Matrix4x4f>(); + m_Device->SetProjectionMatrix(matrix); + break; + } + case kGfxCmd_SetInverseScale: + { + float invScale = stream.ReadValueType<float>(); + m_Device->SetInverseScale(invScale); + break; + } + case kGfxCmd_SetNormalizationBackface: + { + const GfxCmdSetNormalizationBackface& data = stream.ReadValueType<GfxCmdSetNormalizationBackface>(); + CHECK_CACHED_STATE(data.mode != m_Cached.normalization || int(data.backface) != m_Cached.backface) + { + m_Device->SetNormalizationBackface(data.mode, data.backface); + SET_CACHED_STATE(m_Cached.normalization, data.mode); + SET_CACHED_STATE(m_Cached.backface, data.backface); + } + break; + } + case kGfxCmd_SetFFLighting: + { + const GfxCmdSetFFLighting& data = stream.ReadValueType<GfxCmdSetFFLighting>(); + m_Device->SetFFLighting(data.on, data.separateSpecular, data.colorMaterial); + break; + } + case kGfxCmd_SetMaterial: + { + const GfxMaterialParams& mat = stream.ReadValueType<GfxMaterialParams>(); + m_Device->SetMaterial(mat.ambient.GetPtr(), mat.diffuse.GetPtr(), mat.specular.GetPtr(), mat.emissive.GetPtr(), mat.shininess); + break; + } + case kGfxCmd_SetColor: + { + const Vector4f& color = stream.ReadValueType<Vector4f>(); + m_Device->SetColor(color.GetPtr()); + break; + } + case kGfxCmd_SetViewport: + { + const ClientDeviceRect& rect = stream.ReadValueType<ClientDeviceRect>(); + m_Device->SetViewport(rect.x, rect.y, rect.width, rect.height); + break; + } + case kGfxCmd_SetScissorRect: + { + const ClientDeviceRect& rect = stream.ReadValueType<ClientDeviceRect>(); + m_Device->SetScissorRect(rect.x, rect.y, rect.width, rect.height); + break; + } + case kGfxCmd_DisableScissor: + { + m_Device->DisableScissor(); + break; + } + case kGfxCmd_CreateTextureCombiners: + { +#if ENABLE_GFXDEVICE_REMOTE_PROCESS + ClientDeviceTextureCombiners result; + result.internalHandle = stream.ReadValueType<ClientIDMapper::ClientID>(); + result.count = stream.ReadValueType<int>(); + result.bindings = new ShaderLab::TextureBinding[result.count]; + for (int i = 0; i < result.count; i++) + result.bindings[i] = stream.ReadValueType<ShaderLab::TextureBinding>(); + + const GfxCmdCreateTextureCombiners& param = stream.ReadValueType<GfxCmdCreateTextureCombiners>(); + m_TextureCombinerMapper[result.internalHandle] = m_Device->CreateTextureCombiners(param.count, result.bindings, NULL, param.hasVertexColorOrLighting, param.usesAddSpecular).object; +#else + ClientDeviceTextureCombiners* result = stream.ReadValueType<ClientDeviceTextureCombiners*>(); + const GfxCmdCreateTextureCombiners& param = stream.ReadValueType<GfxCmdCreateTextureCombiners>(); + result->internalHandle = m_Device->CreateTextureCombiners(param.count, result->bindings, NULL, param.hasVertexColorOrLighting, param.usesAddSpecular); +#endif + break; + } + case kGfxCmd_DeleteTextureCombiners: + { +#if ENABLE_GFXDEVICE_REMOTE_PROCESS + ClientDeviceTextureCombiners combiners; + combiners.internalHandle = stream.ReadValueType<ClientIDMapper::ClientID>(); + combiners.count = stream.ReadValueType<int>(); + TextureCombinersHandle handle(m_TextureCombinerMapper[combiners.internalHandle]); + m_Device->DeleteTextureCombiners(handle); +#else + ClientDeviceTextureCombiners* combiners = stream.ReadValueType<ClientDeviceTextureCombiners*>(); + m_Device->DeleteTextureCombiners(combiners->internalHandle); + for(int i = 0; i < combiners->count; i++) combiners->bindings[i].~TextureBinding(); + UNITY_FREE(kMemGfxThread,combiners->bindings); + UNITY_DELETE(combiners, kMemGfxThread); +#endif + break; + } + case kGfxCmd_SetTextureCombiners: + { +#if ENABLE_GFXDEVICE_REMOTE_PROCESS + ClientDeviceTextureCombiners combiners; + combiners.internalHandle = stream.ReadValueType<ClientIDMapper::ClientID>(); + combiners.count = stream.ReadValueType<int>(); + int count = combiners.count; +#else + ClientDeviceTextureCombiners* combiners = stream.ReadValueType<ClientDeviceTextureCombiners*>(); + int count = combiners->count; +#endif + const void* data = m_CommandQueue->GetReadDataPointer(count * sizeof(TexEnvData), ALIGN_OF(TexEnvData)); + const TexEnvData* texEnvData = static_cast<const TexEnvData*>(data); + data = m_CommandQueue->GetReadDataPointer(count * sizeof(Vector4f), ALIGN_OF(Vector4f)); + const Vector4f* texColors = static_cast<const Vector4f*>(data); + // CreateTextureCombiners() might have failed on render thread, unknownst to main thread (case 435703) +#if ENABLE_GFXDEVICE_REMOTE_PROCESS + if (combiners.internalHandle) + m_Device->SetTextureCombinersThreadable(TextureCombinersHandle(m_TextureCombinerMapper[combiners.internalHandle]), texEnvData, texColors); +#else + if (combiners->internalHandle.IsValid()) + m_Device->SetTextureCombinersThreadable(combiners->internalHandle, texEnvData, texColors); +#endif + break; + } + case kGfxCmd_SetTexture: + { + const GfxCmdSetTexture& tex = stream.ReadValueType<GfxCmdSetTexture>(); + m_Device->SetTexture(tex.shaderType, tex.unit, tex.samplerUnit, tex.texture, tex.dim, tex.bias); + break; + } + case kGfxCmd_SetTextureParams: + { + const GfxCmdSetTextureParams& params = stream.ReadValueType<GfxCmdSetTextureParams>(); + m_Device->SetTextureParams( params.texture, params.texDim, params.filter, params.wrap, params.anisoLevel, params.hasMipMap, params.colorSpace); + m_CommandQueue->ReadReleaseData(); + break; + } + case kGfxCmd_SetTextureTransform: + { + const GfxCmdSetTextureTransform& trans = stream.ReadValueType<GfxCmdSetTextureTransform>(); + m_Device->SetTextureTransform(trans.unit, trans.dim, trans.texGen, trans.identity, trans.matrix.GetPtr()); + break; + } + case kGfxCmd_SetTextureName: + { + const GfxCmdSetTextureName& texName = stream.ReadValueType<GfxCmdSetTextureName>(); + char* name = m_CommandQueue->ReadArrayType<char>(texName.nameLength); + m_Device->SetTextureName( texName.texture, name ); + break; + } + case kGfxCmd_SetMaterialProperties: + { + typedef MaterialPropertyBlock::Property Property; + GfxCmdSetMaterialProperties matprops = m_CommandQueue->ReadValueType<GfxCmdSetMaterialProperties>(); + Property* props = m_CommandQueue->ReadArrayType<Property>(matprops.propertyCount); + float* buffer = m_CommandQueue->ReadArrayType<float>(matprops.bufferSize); + MaterialPropertyBlock block(props, matprops.propertyCount, buffer, matprops.bufferSize); + m_Device->SetMaterialProperties(block); + break; + } + case kGfxCmd_CreateGpuProgram: + { + #if !ENABLE_GFXDEVICE_REMOTE_PROCESS + GfxCmdCreateGpuProgram gpuprog = m_CommandQueue->ReadValueType<GfxCmdCreateGpuProgram>(); + *gpuprog.result = m_Device->CreateGpuProgram(gpuprog.source, *gpuprog.output); + UnityMemoryBarrier(); + m_WaitSemaphore.Signal(); + m_CommandQueue->ReadReleaseData(); + #else + size_t len = m_CommandQueue->ReadValueType<UInt32>(); + const char* source = m_CommandQueue->ReadArrayType<char>(len + 1); + CreateGpuProgramOutput output; + GpuProgram* program = m_Device->CreateGpuProgram(source, output); + Assert(program); + // Allocate space for struct, append additional data + m_TempBuffer.resize_uninitialized(sizeof(GfxRet_CreateGpuProgram)); + GfxRet_CreateGpuProgram retStruct(output, m_TempBuffer); + retStruct.gpuProgram = m_GpuProgramClientMapper.CreateID(); + m_GpuProgramMapper[retStruct.gpuProgram] = program; + // Copy struct to start of buffer + *reinterpret_cast<GfxRet_CreateGpuProgram*>(m_TempBuffer.data()) = retStruct; + WritebackData(stream, m_TempBuffer.data(), m_TempBuffer.size()); + #endif + break; + } + case kGfxCmd_SetShaders: + { + GfxCmdSetShaders shaders = stream.ReadValueType<GfxCmdSetShaders>(); + UInt8* paramsBuffer[kShaderTypeCount]; +#if ENABLE_GFXDEVICE_REMOTE_PROCESS + const GpuProgramParameters* params[kShaderTypeCount]; + GpuProgram* programs[kShaderTypeCount]; +#endif + for (int pt = 0; pt < kShaderTypeCount; ++pt) + { +#if ENABLE_GFXDEVICE_REMOTE_PROCESS + params[pt] = m_GpuProgramParametersMapper[shaders.params[pt]]; + programs[pt] = m_GpuProgramMapper[shaders.programs[pt]]; +#endif + + paramsBuffer[pt] = NULL; + if (shaders.paramsBufferSize[pt] > 0) + { + void* buffer = m_CommandQueue->GetReadDataPointer (shaders.paramsBufferSize[pt], 1); + paramsBuffer[pt] = static_cast<UInt8*>(buffer); + } + } +#if ENABLE_GFXDEVICE_REMOTE_PROCESS + m_Device->SetShadersThreadable (programs, params, paramsBuffer); +#else + m_Device->SetShadersThreadable (shaders.programs, shaders.params, paramsBuffer); +#endif + break; + } + case kGfxCmd_CreateShaderParameters: + { + GfxCmdCreateShaderParameters params = stream.ReadValueType<GfxCmdCreateShaderParameters>(); + m_Device->CreateShaderParameters(params.program, params.fogMode); + Signal(); + break; + } + case kGfxCmd_DestroySubProgram: + { + ShaderLab::SubProgram* subprogram = stream.ReadValueType<ShaderLab::SubProgram*>(); +#if !ENABLE_GFXDEVICE_REMOTE_PROCESS + m_Device->DestroySubProgram(subprogram); +#else + printf_console("fix ShaderLab::SubProgram\n"); +#endif + break; + } + case kGfxCmd_SetConstantBufferInfo: + { + int id = stream.ReadValueType<int>(); + int size = stream.ReadValueType<int>(); + m_Device->SetConstantBufferInfo (id, size); + break; + } + case kGfxCmd_DisableLights: + { + int startLight = stream.ReadValueType<int>(); + m_Device->DisableLights(startLight); + break; + } + case kGfxCmd_SetLight: + { + int light = stream.ReadValueType<int>(); + const GfxVertexLight& lightdata = stream.ReadValueType<GfxVertexLight>(); + m_Device->SetLight(light, lightdata); + break; + } + case kGfxCmd_SetAmbient: + { + const Vector4f& ambient = stream.ReadValueType<Vector4f>(); + CHECK_CACHED_STATE(!CompareMemory(ambient, m_Cached.ambient)) + { + m_Device->SetAmbient(ambient.GetPtr()); + SET_CACHED_STATE(m_Cached.ambient, ambient); + } + break; + } + case kGfxCmd_EnableFog: + { + const GfxFogParams& fog = stream.ReadValueType<GfxFogParams>(); + CHECK_CACHED_STATE(m_Cached.fogEnabled != 1 || !CompareMemory(fog, m_Cached.fogParams)) + { + m_Device->EnableFog(fog); + SET_CACHED_STATE(m_Cached.fogEnabled, 1); + SET_CACHED_STATE(m_Cached.fogParams, fog); + } + break; + } + case kGfxCmd_DisableFog: + { + CHECK_CACHED_STATE(m_Cached.fogEnabled != 0) + { + m_Device->DisableFog(); + SET_CACHED_STATE(m_Cached.fogEnabled, 0); + } + break; + } + case kGfxCmd_BeginSkinning: + { + int maxSkinCount = stream.ReadValueType<int>(); + m_SkinJobGroup = GetJobScheduler().BeginGroup(maxSkinCount); + m_ActiveSkins.reserve(maxSkinCount); + break; + } + case kGfxCmd_SkinMesh: + { + // Array must be preallocated to at least the right size + Assert(m_ActiveSkins.size() < m_ActiveSkins.capacity()); + int skinIndex = m_ActiveSkins.size(); + m_ActiveSkins.resize_uninitialized(skinIndex + 1); + SkinMeshInfo& skin = m_ActiveSkins[skinIndex]; + skin = stream.ReadValueType<SkinMeshInfo>(); + ClientDeviceVBO* vbo = stream.ReadValueType<ClientDeviceVBO*>(); + stream.ReadReleaseData(); + +#if !ENABLE_GFXDEVICE_REMOTE_PROCESS + VertexStreamData mappedVSD; + if (vbo->GetInternal()->MapVertexStream(mappedVSD, 0)) + { + skin.outVertices = mappedVSD.buffer; + GetJobScheduler().SubmitJob(m_SkinJobGroup, DeformSkinnedMeshJob, &skin, NULL); + m_MappedSkinVBOs.push_back(vbo->GetInternal()); + } +#endif + break; + } + case kGfxCmd_EndSkinning: + { + GetJobScheduler().WaitForGroup(m_SkinJobGroup); + for (int i = 0; i < m_ActiveSkins.size(); i++) + { + m_ActiveSkins[i].Release(); + } + m_ActiveSkins.resize_uninitialized(0); + for (int i = 0; i < m_MappedSkinVBOs.size(); i++) + { + m_MappedSkinVBOs[i]->UnmapVertexStream(0); + } + m_MappedSkinVBOs.resize_uninitialized(0); + break; + } +#if GFX_ENABLE_DRAW_CALL_BATCHING + case kGfxCmd_BeginStaticBatching: + { + PROFILER_BEGIN(gMTDrawStaticBatch, NULL); + const GfxCmdBeginStaticBatching& dynbat = stream.ReadValueType<GfxCmdBeginStaticBatching>(); + m_Device->BeginStaticBatching(dynbat.channels, dynbat.topology); + break; + } + case kGfxCmd_StaticBatchMesh: + { + const GfxCmdStaticBatchMesh& batch = stream.ReadValueType<GfxCmdStaticBatchMesh>(); + m_Device->StaticBatchMesh(batch.firstVertex, batch.vertexCount, + batch.indices, batch.firstIndexByte, batch.indexCount); + stream.ReadReleaseData(); + break; + } + case kGfxCmd_EndStaticBatching: + { + const GfxCmdEndStaticBatching& endbat = stream.ReadValueType<GfxCmdEndStaticBatching>(); + m_Device->EndStaticBatching(*endbat.vbo->GetInternal(), endbat.matrix, endbat.transformType, endbat.sourceChannels); + stream.ReadReleaseData(); + PROFILER_END; + break; + } + case kGfxCmd_BeginDynamicBatching: + { + PROFILER_BEGIN(gMTDrawDynamicBatch, NULL); + const GfxCmdBeginDynamicBatching& dynbat = stream.ReadValueType<GfxCmdBeginDynamicBatching>(); + m_Device->BeginDynamicBatching(dynbat.shaderChannels, dynbat.channelsInVBO, dynbat.maxVertices, dynbat.maxIndices, dynbat.topology); + break; + } + case kGfxCmd_DynamicBatchMesh: + { + const GfxCmdDynamicBatchMesh& batch = stream.ReadValueType<GfxCmdDynamicBatchMesh>(); + m_Device->DynamicBatchMesh(batch.matrix, batch.vertices, batch.firstVertex, batch.vertexCount, + batch.indices, batch.firstIndexByte, batch.indexCount); + stream.ReadReleaseData(); + break; + } +#if ENABLE_SPRITES + case kGfxCmd_DynamicBatchSprite: + { + const GfxCmdDynamicBatchSprite& batch = stream.ReadValueType<GfxCmdDynamicBatchSprite>(); + m_Device->DynamicBatchSprite(&batch.matrix, batch.sprite, batch.color); + stream.ReadReleaseData(); + break; + } +#endif + case kGfxCmd_EndDynamicBatching: + { + const GfxCmdEndDynamicBatching& endbat = stream.ReadValueType<GfxCmdEndDynamicBatching>(); + m_Device->EndDynamicBatching(endbat.transformType); + stream.ReadReleaseData(); + PROFILER_END; + break; + } +#endif + case kGfxCmd_AddBatchingStats: + { + const GfxCmdAddBatchingStats& stats = stream.ReadValueType<GfxCmdAddBatchingStats>(); + m_Device->AddBatchingStats(stats.batchedTris, stats.batchedVerts, stats.batchedCalls); + stream.ReadReleaseData(); + break; + } + case kGfxCmd_CreateRenderColorSurface: + { +#if !ENABLE_GFXDEVICE_REMOTE_PROCESS + ClientDeviceRenderSurface* handle = stream.ReadValueType<ClientDeviceRenderSurface*>(); +#else + ClientDeviceRenderSurface handle = stream.ReadValueType<ClientDeviceRenderSurface>(); +#endif + const GfxCmdCreateRenderColorSurface& create = stream.ReadValueType<GfxCmdCreateRenderColorSurface>(); +#if !ENABLE_GFXDEVICE_REMOTE_PROCESS + handle->internalHandle = m_Device->CreateRenderColorSurface(create.textureID, create.width, create.height, create.samples, create.depth, create.dim, create.format, create.createFlags); +#else + m_RenderSurfaceMapper[handle.internalHandle] = m_Device->CreateRenderColorSurface(create.textureID, create.width, create.height, create.samples, create.depth, create.dim, create.format, create.createFlags).object; +#endif + stream.ReadReleaseData(); + break; + } + case kGfxCmd_CreateRenderDepthSurface: + { +#if !ENABLE_GFXDEVICE_REMOTE_PROCESS + ClientDeviceRenderSurface* handle = stream.ReadValueType<ClientDeviceRenderSurface*>(); +#else + ClientDeviceRenderSurface handle = stream.ReadValueType<ClientDeviceRenderSurface>(); +#endif + const GfxCmdCreateRenderDepthSurface& create = stream.ReadValueType<GfxCmdCreateRenderDepthSurface>(); +#if !ENABLE_GFXDEVICE_REMOTE_PROCESS + handle->internalHandle = m_Device->CreateRenderDepthSurface(create.textureID, create.width, create.height, create.samples, create.dim, create.depthFormat, create.createFlags); +#else + m_RenderSurfaceMapper[handle.internalHandle] = m_Device->CreateRenderDepthSurface(create.textureID, create.width, create.height, create.samples, create.dim, create.depthFormat, create.createFlags).object; +#endif + stream.ReadReleaseData(); + break; + } + case kGfxCmd_DestroyRenderSurface: + { +#if !ENABLE_GFXDEVICE_REMOTE_PROCESS + ClientDeviceRenderSurface* handle = stream.ReadValueType<ClientDeviceRenderSurface*>(); + RenderSurfaceHandle rsHandle = handle->internalHandle; +#else + ClientDeviceRenderSurface handle = stream.ReadValueType<ClientDeviceRenderSurface>(); + RenderSurfaceHandle rsHandle(m_RenderSurfaceMapper[handle.internalHandle]); +#endif + m_Device->DestroyRenderSurface(rsHandle); +#if !ENABLE_GFXDEVICE_REMOTE_PROCESS + delete handle; +#endif + stream.ReadReleaseData(); + break; + } + case kGfxCmd_DiscardContents: + { +#if !ENABLE_GFXDEVICE_REMOTE_PROCESS + ClientDeviceRenderSurface* handle = stream.ReadValueType<ClientDeviceRenderSurface*>(); + RenderSurfaceHandle rsHandle = handle->internalHandle; +#else + ClientDeviceRenderSurface handle = stream.ReadValueType<ClientDeviceRenderSurface>(); + RenderSurfaceHandle rsHandle(m_RenderSurfaceMapper[handle.internalHandle]); +#endif + m_Device->DiscardContents(rsHandle); + stream.ReadReleaseData(); + break; + } + case kGfxCmd_SetRenderTarget: + { + PROFILER_AUTO(gMTSetRT, NULL); + const GfxCmdSetRenderTarget& srt = stream.ReadValueType<GfxCmdSetRenderTarget>(); + RenderSurfaceHandle colorHandle[kMaxSupportedRenderTargets]; + for (int i = 0; i < srt.colorCount; ++i) + { +#if !ENABLE_GFXDEVICE_REMOTE_PROCESS + ClientDeviceRenderSurface* colorSurf = static_cast<ClientDeviceRenderSurface*>(srt.colorHandles[i].object); + colorHandle[i].object = colorSurf ? colorSurf->internalHandle.object : NULL; +#else + colorHandle[i].object = m_RenderSurfaceMapper[srt.colorHandles[i]]; +#endif + // we cant access backbuffer handle in client device, so we write null + if(!colorHandle[i].IsValid()) + colorHandle[i] = m_Device->GetBackBufferColorSurface(); + } +#if !ENABLE_GFXDEVICE_REMOTE_PROCESS + ClientDeviceRenderSurface* depthSurf = (ClientDeviceRenderSurface*)srt.depthHandle.object; + RenderSurfaceHandle depthHandle(depthSurf ? depthSurf->internalHandle.object :NULL); +#else + RenderSurfaceHandle depthHandle(m_RenderSurfaceMapper[srt.depthHandle]); +#endif + // we cant access backbuffer handle in client device, so we write null + if(!depthHandle.IsValid()) + depthHandle = m_Device->GetBackBufferDepthSurface(); + + m_Device->SetRenderTargets (srt.colorCount, colorHandle, depthHandle, srt.mipLevel, srt.face); + stream.ReadReleaseData(); + break; + } + case kGfxCmd_SetRenderTargetWithFlags: + { + PROFILER_AUTO(gMTSetRT, NULL); + const GfxCmdSetRenderTarget& srt = stream.ReadValueType<GfxCmdSetRenderTarget>(); + RenderSurfaceHandle colorHandle[kMaxSupportedRenderTargets]; + for (int i = 0; i < srt.colorCount; ++i) + { +#if !ENABLE_GFXDEVICE_REMOTE_PROCESS + ClientDeviceRenderSurface* colorSurf = static_cast<ClientDeviceRenderSurface*>(srt.colorHandles[i].object); + colorHandle[i].object = colorSurf ? colorSurf->internalHandle.object : NULL; +#else + colorHandle[i].object = m_RenderSurfaceMapper[srt.colorHandles[i]]; +#endif + // we cant access backbuffer handle in client device, so we write null + if(!colorHandle[i].IsValid()) + colorHandle[i] = m_Device->GetBackBufferColorSurface(); + } +#if !ENABLE_GFXDEVICE_REMOTE_PROCESS + ClientDeviceRenderSurface* depthSurf = (ClientDeviceRenderSurface*)srt.depthHandle.object; + RenderSurfaceHandle depthHandle(depthSurf ? depthSurf->internalHandle.object :NULL); +#else + RenderSurfaceHandle depthHandle(m_RenderSurfaceMapper[srt.depthHandle]); +#endif + // we cant access backbuffer handle in client device, so we write null + if(!depthHandle.IsValid()) + depthHandle = m_Device->GetBackBufferDepthSurface(); + + UInt32 flags = stream.ReadValueType<UInt32>(); + m_Device->SetRenderTargets (srt.colorCount, colorHandle, depthHandle, srt.mipLevel, srt.face, flags); + stream.ReadReleaseData(); + break; + } + case kGfxCmd_ResolveColorSurface: + { +#if !ENABLE_GFXDEVICE_REMOTE_PROCESS + ClientDeviceRenderSurface* src = stream.ReadValueType<ClientDeviceRenderSurface*>(); + ClientDeviceRenderSurface* dst = stream.ReadValueType<ClientDeviceRenderSurface*>(); + m_Device->ResolveColorSurface (src->internalHandle, dst->internalHandle); +#else + //todo +#endif + stream.ReadReleaseData(); + break; + } + case kGfxCmd_ResolveDepthIntoTexture: + { + const GfxCmdResolveDepthIntoTexture resolve = stream.ReadValueType<GfxCmdResolveDepthIntoTexture>(); +#if !ENABLE_GFXDEVICE_REMOTE_PROCESS + ClientDeviceRenderSurface* colorSurf = (ClientDeviceRenderSurface*)resolve.colorHandle.object; + RenderSurfaceHandle colorHandle(colorSurf ? colorSurf->internalHandle.object : NULL); + + ClientDeviceRenderSurface* depthSurf = (ClientDeviceRenderSurface*)resolve.depthHandle.object; + RenderSurfaceHandle depthHandle(depthSurf ? depthSurf->internalHandle.object : NULL); +#else + RenderSurfaceHandle colorHandle(m_RenderSurfaceMapper[resolve.colorHandle]); + RenderSurfaceHandle depthHandle(m_RenderSurfaceMapper[resolve.depthHandle]); +#endif + m_Device->ResolveDepthIntoTexture (colorHandle, depthHandle); + stream.ReadReleaseData(); + break; + } + case kGfxCmd_SetSurfaceFlags: + { + const GfxCmdSetSurfaceFlags& sf = stream.ReadValueType<GfxCmdSetSurfaceFlags>(); +#if !ENABLE_GFXDEVICE_REMOTE_PROCESS + ClientDeviceRenderSurface* surface = (ClientDeviceRenderSurface*)sf.surf.object; + RenderSurfaceHandle handle = surface->internalHandle; +#else + RenderSurfaceHandle handle(m_RenderSurfaceMapper[sf.surf]); +#endif + m_Device->SetSurfaceFlags(handle, sf.flags, sf.keepFlags); + stream.ReadReleaseData(); + break; + } + case kGfxCmd_UploadTexture2D: + { + // Must copy since we stream data + GfxCmdUploadTexture2D upload = stream.ReadValueType<GfxCmdUploadTexture2D>(); + UInt8* srcData = ReadBufferData(stream, upload.srcSize); + m_Device->UploadTexture2D(upload.texture, upload.dimension, srcData, upload.srcSize, + upload.width, upload.height, upload.format, upload.mipCount, upload.uploadFlags, + upload.skipMipLevels, upload.usageMode, upload.colorSpace); + stream.ReadReleaseData(); + break; + } + case kGfxCmd_UploadTextureSubData2D: + { + // Must copy since we stream data + GfxCmdUploadTextureSubData2D upload = stream.ReadValueType<GfxCmdUploadTextureSubData2D>(); + UInt8* srcData = ReadBufferData(stream, upload.srcSize); + m_Device->UploadTextureSubData2D(upload.texture, srcData, upload.srcSize, + upload.mipLevel, upload.x, upload.y, upload.width, upload.height, upload.format, upload.colorSpace); + stream.ReadReleaseData(); + break; + } + case kGfxCmd_UploadTextureCube: + { + // Must copy since we stream data + GfxCmdUploadTextureCube upload = stream.ReadValueType<GfxCmdUploadTextureCube>(); + UInt8* srcData = ReadBufferData(stream, upload.srcSize); + m_Device->UploadTextureCube(upload.texture, srcData, upload.srcSize, + upload.faceDataSize, upload.size, upload.format, upload.mipCount, upload.uploadFlags, upload.colorSpace); + stream.ReadReleaseData(); + break; + } + case kGfxCmd_UploadTexture3D: + { + // Must copy since we stream data + GfxCmdUploadTexture3D upload = stream.ReadValueType<GfxCmdUploadTexture3D>(); + UInt8* srcData = ReadBufferData(stream, upload.srcSize); + m_Device->UploadTexture3D(upload.texture, srcData, upload.srcSize, + upload.width, upload.height, upload.depth, upload.format, upload.mipCount, upload.uploadFlags); + stream.ReadReleaseData(); + break; + } + case kGfxCmd_DeleteTexture: + { + TextureID texture = stream.ReadValueType<TextureID>(); + m_Device->DeleteTexture(texture); + stream.ReadReleaseData(); + break; + } + case kGfxCmd_BeginFrame: + { + m_Device->BeginFrame(); + break; + } + case kGfxCmd_EndFrame: + { + m_Device->EndFrame(); + break; + } + case kGfxCmd_PresentFrame: + { + PROFILER_AUTO(gMTPresentFrame, NULL); + m_Device->PresentFrame(); + GfxCmdBool signalEvent = stream.ReadValueType<GfxCmdBool>(); + if (signalEvent) + SignalEvent(kEventTypePresent); + UnityMemoryBarrier(); + m_PresentFrameID = stream.ReadValueType<UInt32>(); + break; + } + case kGfxCmd_HandleInvalidState: + { + bool* success = stream.ReadValueType<bool*>(); + *success = m_Device->HandleInvalidState(); + Signal(); + break; + } + case kGfxCmd_FinishRendering: + { + m_Device->FinishRendering(); + Signal(); + break; + } + case kGfxCmd_InsertCPUFence: + { + stream.ReadReleaseData(); + m_CurrentCPUFence++; + break; + } + case kGfxCmd_ImmediateVertex: + { + const GfxCmdVector3& data = stream.ReadValueType<GfxCmdVector3>(); + m_Device->ImmediateVertex(data.x, data.y, data.z); + stream.ReadReleaseData(); + break; + } + case kGfxCmd_ImmediateNormal: + { + const GfxCmdVector3& data = stream.ReadValueType<GfxCmdVector3>(); + m_Device->ImmediateNormal(data.x, data.y, data.z); + stream.ReadReleaseData(); + break; + } + case kGfxCmd_ImmediateColor: + { + const GfxCmdVector4& data = stream.ReadValueType<GfxCmdVector4>(); + m_Device->ImmediateColor(data.x, data.y, data.z, data.w); + stream.ReadReleaseData(); + break; + } + case kGfxCmd_ImmediateTexCoordAll: + { + const GfxCmdVector3& data = stream.ReadValueType<GfxCmdVector3>(); + m_Device->ImmediateTexCoordAll(data.x, data.y, data.z); + stream.ReadReleaseData(); + break; + } + case kGfxCmd_ImmediateTexCoord: + { + const GfxCmdImmediateTexCoord& data = stream.ReadValueType<GfxCmdImmediateTexCoord>(); + m_Device->ImmediateTexCoord(data.unit, data.x, data.y, data.z); + stream.ReadReleaseData(); + break; + } + case kGfxCmd_ImmediateBegin: + { + const GfxPrimitiveType& data = stream.ReadValueType<GfxPrimitiveType>(); + m_Device->ImmediateBegin(data); + break; + } + case kGfxCmd_ImmediateEnd: + { + m_Device->ImmediateEnd(); + stream.ReadReleaseData(); + break; + } + case kGfxCmd_CaptureScreenshot: + { + const GfxCmdCaptureScreenshot& capture = stream.ReadValueType<GfxCmdCaptureScreenshot>(); + *capture.success = m_Device->CaptureScreenshot(capture.left, capture.bottom, capture.width, capture.height, capture.rgba32); + stream.ReadReleaseData(); + Signal(); + break; + } + case kGfxCmd_ReadbackImage: + { + const GfxCmdReadbackImage& read = stream.ReadValueType<GfxCmdReadbackImage>(); +#if !ENABLE_GFXDEVICE_REMOTE_PROCESS + *read.success = m_Device->ReadbackImage(read.image, read.left, read.bottom, read.width, read.height, read.destX, read.destY); +#else + //todo +#endif + stream.ReadReleaseData(); + Signal(); + break; + } + case kGfxCmd_GrabIntoRenderTexture: + { + const GfxCmdGrabIntoRenderTexture& grab = stream.ReadValueType<GfxCmdGrabIntoRenderTexture>(); +#if !ENABLE_GFXDEVICE_REMOTE_PROCESS + ClientDeviceRenderSurface* surf = (ClientDeviceRenderSurface*)grab.rs.object; + RenderSurfaceHandle handle(surf ? surf->internalHandle.object : NULL); + ClientDeviceRenderSurface* surfZ = (ClientDeviceRenderSurface*)grab.rd.object; + RenderSurfaceHandle handleZ(surfZ ? surfZ->internalHandle.object : NULL); +#else + RenderSurfaceHandle handle(m_RenderSurfaceMapper[grab.rs]); + RenderSurfaceHandle handleZ(m_RenderSurfaceMapper[grab.rd]); +#endif + m_Device->GrabIntoRenderTexture(handle, handleZ, grab.x, grab.y, grab.width, grab.height); + stream.ReadReleaseData(); + break; + } + case kGfxCmd_SetActiveContext: + { + void* ctx = stream.ReadValueType<void*>(); + m_Device->SetActiveContext (ctx); + Signal(); + break; + } + case kGfxCmd_ResetFrameStats: + { + m_Device->ResetFrameStats(); + break; + } + case kGfxCmd_BeginFrameStats: + { + m_Device->GetFrameStats().BeginFrameStats(); + stream.ResetReadWaitTime(); + break; + } + case kGfxCmd_EndFrameStats: + { + GfxDeviceStats& stats = m_Device->GetFrameStats(); + stats.EndRenderFrameStats(); + stats.m_RenderFrameTime -= stream.GetReadWaitTime(); + break; + } + case kGfxCmd_SaveDrawStats: + { + m_Device->SaveDrawStats(); + break; + } + case kGfxCmd_RestoreDrawStats: + { + m_Device->RestoreDrawStats(); + break; + } + case kGfxCmd_SynchronizeStats: + { + Mutex::AutoLock lock(m_StatsMutex); + m_Device->GetFrameStats().AccumulateUsedTextureUsage(); + m_FrameStats = m_Device->GetFrameStats(); + break; + } +#if UNITY_EDITOR + case kGfxCmd_SetAntiAliasFlag: + { + bool aa = stream.ReadValueType<GfxCmdBool>(); + m_Device->SetAntiAliasFlag(aa); + break; + } + case kGfxCmd_DrawUserPrimitives: + { + GfxCmdDrawUserPrimitives user = stream.ReadValueType<GfxCmdDrawUserPrimitives>(); + int dataSize = user.vertexCount * user.stride; + m_TempBuffer.resize_uninitialized(dataSize); + stream.ReadStreamingData(m_TempBuffer.data(), dataSize); + m_Device->DrawUserPrimitives(user.type, user.vertexCount, user.vertexChannels, m_TempBuffer.data(), user.stride); + break; + } +#endif + case kGfxCmd_Quit: + { + m_Quit = true; + Signal(); + break; + } + case kGfxCmd_InsertCustomMarker: + { + int marker = stream.ReadValueType<int>(); + m_Device->InsertCustomMarker (marker); + break; + } + case kGfxCmd_SetComputeBufferData: + { + ComputeBufferID buffer = stream.ReadValueType<ComputeBufferID>(); + size_t size = stream.ReadValueType<size_t>(); + DebugAssert (size); + m_TempBuffer.resize_uninitialized(size); + stream.ReadStreamingData(&m_TempBuffer[0], size); + m_Device->SetComputeBufferData (buffer, m_TempBuffer.data(), size); + break; + } + case kGfxCmd_GetComputeBufferData: + { + ComputeBufferID buffer = stream.ReadValueType<ComputeBufferID>(); + size_t size = stream.ReadValueType<size_t>(); + void* ptr = stream.ReadValueType<void*>(); + DebugAssert (size && ptr); + m_Device->GetComputeBufferData (buffer, ptr, size); + stream.ReadReleaseData(); + Signal(); + break; + } + case kGfxCmd_CopyComputeBufferCount: + { + ComputeBufferID srcBuffer = stream.ReadValueType<ComputeBufferID>(); + ComputeBufferID dstBuffer = stream.ReadValueType<ComputeBufferID>(); + UInt32 dstOffset = stream.ReadValueType<UInt32>(); + m_Device->CopyComputeBufferCount (srcBuffer, dstBuffer, dstOffset); + break; + } + case kGfxCmd_SetRandomWriteTargetTexture: + { + int index = stream.ReadValueType<int>(); + TextureID tid = stream.ReadValueType<TextureID>(); + m_Device->SetRandomWriteTargetTexture (index, tid); + break; + } + case kGfxCmd_SetRandomWriteTargetBuffer: + { + int index = stream.ReadValueType<int>(); + ComputeBufferID buffer = stream.ReadValueType<ComputeBufferID>(); + m_Device->SetRandomWriteTargetBuffer (index, buffer); + break; + } + case kGfxCmd_ClearRandomWriteTargets: + { + m_Device->ClearRandomWriteTargets (); + break; + } + case kGfxCmd_CreateComputeProgram: + { + ClientDeviceComputeProgram* handle = stream.ReadValueType<ClientDeviceComputeProgram*>(); + size_t size = stream.ReadValueType<size_t>(); + m_TempBuffer.resize_uninitialized(size); + stream.ReadStreamingData(&m_TempBuffer[0], size); + handle->internalHandle = m_Device->CreateComputeProgram (&m_TempBuffer[0], m_TempBuffer.size()); + break; + } + case kGfxCmd_DestroyComputeProgram: + { + ClientDeviceComputeProgram* handle = stream.ReadValueType<ClientDeviceComputeProgram*>(); + DebugAssert (handle); + m_Device->DestroyComputeProgram (handle->internalHandle); + UNITY_DELETE(handle, kMemGfxThread); + break; + } + case kGfxCmd_CreateComputeConstantBuffers: + { + unsigned count = stream.ReadValueType<unsigned>(); + Assert (count <= kMaxSupportedConstantBuffers); + ClientDeviceConstantBuffer* clientCBs[kMaxSupportedConstantBuffers]; + UInt32 cbSizes[kMaxSupportedConstantBuffers]; + for (unsigned i = 0; i < count; ++i) + { + clientCBs[i] = stream.ReadValueType<ClientDeviceConstantBuffer*>(); + DebugAssert (clientCBs[i]); + cbSizes[i] = clientCBs[i]->size; + } + + ConstantBufferHandle cbHandles[kMaxSupportedConstantBuffers]; + m_Device->CreateComputeConstantBuffers (count, cbSizes, cbHandles); + for (unsigned i = 0; i < count; ++i) + clientCBs[i]->internalHandle = cbHandles[i]; + + stream.ReadReleaseData(); + break; + } + case kGfxCmd_DestroyComputeConstantBuffers: + { + unsigned count = stream.ReadValueType<unsigned>(); + Assert (count <= kMaxSupportedConstantBuffers); + ConstantBufferHandle cbHandles[kMaxSupportedConstantBuffers]; + for (unsigned i = 0; i < count; ++i) + { + ClientDeviceConstantBuffer* handle = stream.ReadValueType<ClientDeviceConstantBuffer*>(); + if (handle) + { + cbHandles[i] = handle->internalHandle; + UNITY_DELETE(handle, kMemGfxThread); + } + } + m_Device->DestroyComputeConstantBuffers (count, cbHandles); + stream.ReadReleaseData(); + break; + } + case kGfxCmd_CreateComputeBuffer: + { + ComputeBufferID buffer = stream.ReadValueType<ComputeBufferID>(); + size_t count = stream.ReadValueType<size_t>(); + size_t stride = stream.ReadValueType<size_t>(); + UInt32 flags = stream.ReadValueType<UInt32>(); + m_Device->CreateComputeBuffer (buffer, count, stride, flags); + break; + } + case kGfxCmd_DestroyComputeBuffer: + { + ComputeBufferID buffer = stream.ReadValueType<ComputeBufferID>(); + m_Device->DestroyComputeBuffer (buffer); + break; + } + case kGfxCmd_UpdateComputeConstantBuffers: + { + unsigned count = stream.ReadValueType<unsigned>(); + Assert (count <= kMaxSupportedConstantBuffers); + UInt32 cbDirty = stream.ReadValueType<UInt32>(); + + ConstantBufferHandle cbHandles[kMaxSupportedConstantBuffers]; + UInt32 cbSizes[kMaxSupportedConstantBuffers]; + UInt32 cbOffsets[kMaxSupportedConstantBuffers]; + int bindPoints[kMaxSupportedConstantBuffers]; + for (unsigned i = 0; i < count; ++i) + { + ClientDeviceConstantBuffer* handle = stream.ReadValueType<ClientDeviceConstantBuffer*>(); + if (handle) + cbHandles[i] = handle->internalHandle; + cbSizes[i] = stream.ReadValueType<UInt32>(); + cbOffsets[i] = stream.ReadValueType<UInt32>(); + bindPoints[i] = stream.ReadValueType<int>(); + } + size_t dataSize = stream.ReadValueType<size_t>(); + DebugAssert (dataSize); + m_TempBuffer.resize_uninitialized(dataSize); + stream.ReadStreamingData(&m_TempBuffer[0], dataSize); + + m_Device->UpdateComputeConstantBuffers (count, cbHandles, cbDirty, dataSize, &m_TempBuffer[0], cbSizes, cbOffsets, bindPoints); + stream.ReadReleaseData(); + break; + } + case kGfxCmd_UpdateComputeResources: + { + TextureID textures[kMaxSupportedComputeResources]; + int texBindPoints[kMaxSupportedComputeResources]; + unsigned samplers[kMaxSupportedComputeResources]; + ComputeBufferID inBuffers[kMaxSupportedComputeResources]; + int inBufferBindPoints[kMaxSupportedComputeResources]; + ComputeBufferID outBuffers[kMaxSupportedComputeResources]; + TextureID outTextures[kMaxSupportedComputeResources]; + UInt32 outBufferBindPoints[kMaxSupportedComputeResources]; + + unsigned texCount = stream.ReadValueType<unsigned>(); + for (int i = 0; i < texCount; ++i) + { + textures[i] = stream.ReadValueType<TextureID>(); + texBindPoints[i] = stream.ReadValueType<int>(); + } + unsigned samplerCount = stream.ReadValueType<unsigned>(); + for (int i = 0; i < samplerCount; ++i) + { + samplers[i] = stream.ReadValueType<unsigned>(); + } + unsigned inBufferCount = stream.ReadValueType<unsigned>(); + for (int i = 0; i < inBufferCount; ++i) + { + inBuffers[i] = stream.ReadValueType<ComputeBufferID>(); + inBufferBindPoints[i] = stream.ReadValueType<int>(); + } + unsigned outBufferCount = stream.ReadValueType<unsigned>(); + for (int i = 0; i < outBufferCount; ++i) + { + outBuffers[i] = stream.ReadValueType<ComputeBufferID>(); + outTextures[i] = stream.ReadValueType<TextureID>(); + outBufferBindPoints[i] = stream.ReadValueType<UInt32>(); + } + m_Device->UpdateComputeResources (texCount, textures, texBindPoints, samplerCount, samplers, inBufferCount, inBuffers, inBufferBindPoints, outBufferCount, outBuffers, outTextures, outBufferBindPoints); + stream.ReadReleaseData(); + break; + } + case kGfxCmd_DispatchComputeProgram: + { + ClientDeviceComputeProgram* cp = stream.ReadValueType<ClientDeviceComputeProgram*>(); + DebugAssert (cp); + unsigned threadsX = stream.ReadValueType<unsigned>(); + unsigned threadsY = stream.ReadValueType<unsigned>(); + unsigned threadsZ = stream.ReadValueType<unsigned>(); + m_Device->DispatchComputeProgram (cp->internalHandle, threadsX, threadsY, threadsZ); + break; + } + case kGfxCmd_DrawNullGeometry: + { + GfxPrimitiveType topology = stream.ReadValueType<GfxPrimitiveType>(); + int vertexCount = stream.ReadValueType<int>(); + int instanceCount = stream.ReadValueType<int>(); + m_Device->DrawNullGeometry (topology, vertexCount, instanceCount); + break; + } + case kGfxCmd_DrawNullGeometryIndirect: + { + GfxPrimitiveType topology = stream.ReadValueType<GfxPrimitiveType>(); + ComputeBufferID bufferHandle = stream.ReadValueType<ComputeBufferID>(); + UInt32 bufferOffset = stream.ReadValueType<UInt32>(); + m_Device->DrawNullGeometryIndirect (topology, bufferHandle, bufferOffset); + break; + } + case kGfxCmd_VBO_UpdateVertexData: + { +#if ENABLE_GFXDEVICE_REMOTE_PROCESS + ClientDeviceVBO vbo = stream.ReadValueType<ClientDeviceVBO>(); + ClientVertexBufferData client; + client = stream.ReadValueType<ClientVertexBufferData>(); + VertexBufferData data; + memcpy (data.channels, client.channels, sizeof(ChannelInfoArray)); + memcpy (data.streams, client.streams, sizeof(StreamInfoArray)); + data.bufferSize = client.bufferSize; + data.vertexCount = client.vertexCount; + data.buffer = (UInt8*)client.hasData; +#else + ClientDeviceVBO* vbo = stream.ReadValueType<ClientDeviceVBO*>(); + VertexBufferData data = stream.ReadValueType<VertexBufferData>(); +#endif + // Note! Buffer pointer is no longer valid but we use it to tell if data was written or not + if (data.buffer) + data.buffer = ReadBufferData(stream, data.bufferSize); +#if ENABLE_GFXDEVICE_REMOTE_PROCESS + m_VBOMapper[vbo.internalVBO]->UpdateVertexData(data); +#else + vbo->GetInternal()->UpdateVertexData(data); +#endif + stream.ReadReleaseData(); + break; + } + case kGfxCmd_VBO_UpdateIndexData: + { +#if ENABLE_GFXDEVICE_REMOTE_PROCESS + ClientDeviceVBO vbo = stream.ReadValueType<ClientDeviceVBO>(); +#else + ClientDeviceVBO* vbo = stream.ReadValueType<ClientDeviceVBO*>(); +#endif + IndexBufferData data; + data.count = stream.ReadValueType<int>(); + data.hasTopologies = stream.ReadValueType<UInt32>(); + int bufferSize = data.count * kVBOIndexSize; + data.indices = ReadBufferData(stream, bufferSize); +#if ENABLE_GFXDEVICE_REMOTE_PROCESS + m_VBOMapper[vbo.internalVBO]->UpdateIndexData(data); +#else + vbo->GetInternal()->UpdateIndexData(data); +#endif + stream.ReadReleaseData(); + break; + } + case kGfxCmd_VBO_Draw: + { + PROFILER_AUTO(gMTDrawProf, NULL); + const GfxCmdVBODraw& data = stream.ReadValueType<GfxCmdVBODraw>(); +#if ENABLE_GFXDEVICE_REMOTE_PROCESS + Assert(data.vbo.internalVBO); + m_VBOMapper[data.vbo.internalVBO]->DrawVBO (data.channels, data.firstIndexByte, data.indexCount, + data.topology, data.firstVertex, data.vertexCount); +#else + Assert(data.vbo && data.vbo->GetInternal()); + data.vbo->GetInternal()->DrawVBO (data.channels, data.firstIndexByte, data.indexCount, + data.topology, data.firstVertex, data.vertexCount); +#endif + stream.ReadReleaseData(); + break; + } +#if GFX_ENABLE_DRAW_CALL_BATCHING + case kGfxCmd_VBO_DrawCustomIndexed: + { + PROFILER_AUTO(gMTDrawProf, NULL); + GfxCmdVBODrawCustomIndexed data = stream.ReadValueType<GfxCmdVBODrawCustomIndexed>(); + int dataSize = data.indexCount * kVBOIndexSize; + m_TempBuffer.resize_uninitialized(dataSize); + + stream.ReadStreamingData(m_TempBuffer.data(), dataSize); + data.vbo->GetInternal()->DrawCustomIndexed(data.channels, m_TempBuffer.data(), data.indexCount, + data.topology, data.vertexRangeBegin, data.vertexRangeEnd, data.drawVertexCount); + break; + } +#endif +#if UNITY_XENON + case kGfxCmd_VBO_AddExtraUvChannels: + { + GfxCmdVBOAddExtraUvChannels adduv = stream.ReadValueType<GfxCmdVBOAddExtraUvChannels>(); + m_TempBuffer.resize_uninitialized(adduv.size); + stream.ReadStreamingData(m_TempBuffer.data(), adduv.size); + adduv.vbo->GetInternal()->AddExtraUvChannels(m_TempBuffer.data(), adduv.size, adduv.extraUvCount); + break; + } + case kGfxCmd_VBO_CopyExtraUvChannels: + { + GfxCmdVBOCopyExtraUvChannels copyuv = stream.ReadValueType<GfxCmdVBOCopyExtraUvChannels>(); + copyuv.dest->GetInternal()->CopyExtraUvChannels(copyuv.source->GetInternal()); + break; + } +#endif + case kGfxCmd_VBO_Recreate: + { +#if ENABLE_GFXDEVICE_REMOTE_PROCESS + ClientDeviceVBO vbo = stream.ReadValueType<ClientDeviceVBO>(); + m_VBOMapper[vbo.GetInternal()]->Recreate(); +#else + ClientDeviceVBO* vbo = stream.ReadValueType<ClientDeviceVBO*>(); + vbo->GetInternal()->Recreate(); +#endif + break; + } + case kGfxCmd_VBO_MapVertexStream: + { + // Release any old data + stream.ReadReleaseData(); + // This must be a reference since struct is updated by client thread + const GfxCmdVBOMapVertexStream& map = stream.ReadValueType<GfxCmdVBOMapVertexStream>(); +#if ENABLE_GFXDEVICE_REMOTE_PROCESS + const ClientDeviceVBO& vbo = map.vbo; +#else + ClientDeviceVBO* vbo = map.vbo; +#endif + int size = map.size; + void* dest = NULL; + VertexStreamData mappedVSD; + if (m_Device->IsValidState()) + { +#if ENABLE_GFXDEVICE_REMOTE_PROCESS + if (m_VBOMapper[vbo.internalVBO]->MapVertexStream(mappedVSD, map.stream)) +#else + if (vbo->GetInternal()->MapVertexStream(mappedVSD, map.stream)) +#endif + { + Assert(mappedVSD.buffer); + dest = mappedVSD.buffer; + } + else + ErrorString("Failed to map vertex stream!"); + } + + // ReadStreamingData will skip data if dest is NULL + stream.ReadStreamingData(dest, size); + + if (dest) + { +#if ENABLE_GFXDEVICE_REMOTE_PROCESS + m_VBOMapper[vbo.internalVBO]->UnmapVertexStream(map.stream); +#else + vbo->GetInternal()->UnmapVertexStream(map.stream); +#endif + } + break; + } + case kGfxCmd_VBO_SetVertexStreamMode: + { + GfxCmdVBOSetVertexStreamMode vsmode = stream.ReadValueType<GfxCmdVBOSetVertexStreamMode>(); +#if ENABLE_GFXDEVICE_REMOTE_PROCESS + m_VBOMapper[vsmode.vbo.GetInternal()]->SetVertexStreamMode(vsmode.stream, VBO::StreamMode(vsmode.mode)); +#else + vsmode.vbo->GetInternal()->SetVertexStreamMode(vsmode.stream, VBO::StreamMode(vsmode.mode)); +#endif + break; + } + case kGfxCmd_VBO_SetIndicesDynamic: + { + GfxCmdVBOSetSetIndicesDynamic vsdyn = stream.ReadValueType<GfxCmdVBOSetSetIndicesDynamic>(); +#if ENABLE_GFXDEVICE_REMOTE_PROCESS + m_VBOMapper[vsdyn.vbo.GetInternal()]->SetIndicesDynamic(vsdyn.dynamic); +#else + vsdyn.vbo->GetInternal()->SetIndicesDynamic(vsdyn.dynamic); +#endif + break; + } + case kGfxCmd_VBO_UseAsStreamOutput: + { +#if ENABLE_GFXDEVICE_REMOTE_PROCESS + ClientDeviceVBO vbo = stream.ReadValueType<ClientDeviceVBO>(); + m_VBOMapper[vbo.internalVBO]->UseAsStreamOutput(); +#else + ClientDeviceVBO *vbo = stream.ReadValueType<ClientDeviceVBO *>(); + vbo->GetInternal()->UseAsStreamOutput(); +#endif + break; + } + case kGfxCmd_VBO_Constructor: + { +#if ENABLE_GFXDEVICE_REMOTE_PROCESS + ClientDeviceVBO vbo = stream.ReadValueType<ClientDeviceVBO>(); + m_VBOMapper[vbo.internalVBO] = m_Device->CreateVBO(); +#else + ClientDeviceVBO* vbo = stream.ReadValueType<ClientDeviceVBO*>(); + vbo->internalVBO = m_Device->CreateVBO(); +#endif + break; + } + case kGfxCmd_VBO_Destructor: + { +#if ENABLE_GFXDEVICE_REMOTE_PROCESS + ClientDeviceVBO vbo = stream.ReadValueType<ClientDeviceVBO>(); + m_Device->DeleteVBO(m_VBOMapper[vbo.internalVBO]); +#else + ClientDeviceVBO* vbo = stream.ReadValueType<ClientDeviceVBO*>(); + m_Device->DeleteVBO(vbo->GetInternal()); + UNITY_DELETE( vbo, kMemGfxThread); +#endif + break; + } + case kGfxCmd_DynVBO_Chunk: + { + GfxCmdDynVboChunk chunk = m_CommandQueue->ReadValueType<GfxCmdDynVboChunk>(); + DynamicVBO& vbo = m_Device->GetDynamicVBO(); + void* vertexData; + void* indexData; + void** indexDataPtr = (chunk.actualIndices > 0) ? &indexData :NULL; + bool res = vbo.GetChunk(chunk.channelMask, chunk.actualVertices, chunk.actualIndices, DynamicVBO::RenderMode(chunk.renderMode), &vertexData, indexDataPtr); + if (!res) vertexData = indexData = NULL; + + m_CommandQueue->ReadStreamingData(vertexData, chunk.actualVertices * chunk.vertexStride); + if (chunk.actualIndices > 0) + m_CommandQueue->ReadStreamingData(indexData, chunk.actualIndices * kVBOIndexSize); + + if (res) vbo.ReleaseChunk(chunk.actualVertices, chunk.actualIndices); + + m_CommandQueue->ReadReleaseData(); + break; + } + case kGfxCmd_DynVBO_DrawChunk: + { + PROFILER_AUTO(gMTDrawDynamicProf, NULL); + const ChannelAssigns& channels = m_CommandQueue->ReadValueType<ChannelAssigns>(); + DynamicVBO& vbo = m_Device->GetDynamicVBO(); + vbo.DrawChunk(channels); + m_CommandQueue->ReadReleaseData(); + break; + } + case kGfxCmd_DisplayList_Call: + { + ThreadedDisplayList* dlist = m_CommandQueue->ReadValueType<ThreadedDisplayList*>(); + Assert(m_CallDepth < m_MaxCallDepth); + dlist->Patch(*m_CommandQueue); + m_PlaybackDisplayLists[m_CallDepth] = dlist; + m_CommandQueue = &m_PlaybackCommandQueues[m_CallDepth]; + m_CommandQueue->CreateReadOnly(dlist->GetData(), dlist->GetSize()); + m_CallDepth++; + break; + } + case kGfxCmd_DisplayList_End: + { + Assert(m_CallDepth > 0); + m_CallDepth--; + SAFE_RELEASE(m_PlaybackDisplayLists[m_CallDepth]); + if (m_CallDepth > 0) + m_CommandQueue = &m_PlaybackCommandQueues[m_CallDepth - 1]; + else + m_CommandQueue = m_MainCommandQueue; + break; + } + case kGfxCmd_QueryGraphicsCaps: + { + // no, really, we need to properly serialize this stuff with all the strings. this is just a hack to get running. + size_t offset = (char*)&gGraphicsCaps.vendorID - (char*)&gGraphicsCaps; + WritebackData(stream, &gGraphicsCaps.vendorID, sizeof(GraphicsCaps) - offset); + break; + } +#if ENABLE_GFXDEVICE_REMOTE_PROCESS + case kGfxCmd_SetGpuProgramParameters: + { + ClientIDMapper::ClientID internalHandle = stream.ReadValueType<ClientIDMapper::ClientID>(); + GpuProgramParameters* gpu = new GpuProgramParameters; + Gfx_GpuProgramParameters gfxParams = stream.ReadValueType<Gfx_GpuProgramParameters>(); + int outSize = stream.ReadValueType<UInt32>(); + int strSize = stream.ReadValueType<UInt32>(); + + char* buffer = (char*)m_CommandQueue->GetReadDataPointer (outSize+strSize, 1); + char* strBuf = buffer + outSize; + gfxParams.GetOutput(*gpu, buffer, strBuf, strSize); + m_GpuProgramParametersMapper[internalHandle] = gpu; + break; + } +#endif +#if UNITY_EDITOR && UNITY_WIN + case kGfxCmd_CreateWindow: + { + ClientDeviceWindow* handle = stream.ReadValueType<ClientDeviceWindow*>(); + const GfxCmdCreateWindow& upload = stream.ReadValueType<GfxCmdCreateWindow>(); + handle->internalWindow = m_Device->CreateGfxWindow(upload.window, upload.width, upload.height, upload.depthFormat, upload.antiAlias); + break; + } + case kGfxCmd_SetActiveWindow: + { + ClientDeviceWindow* handle = stream.ReadValueType<ClientDeviceWindow*>(); + handle->GetInternal()->SetAsActiveWindow(); + break; + } + case kGfxCmd_WindowReshape: + { + ClientDeviceWindow* handle = stream.ReadValueType<ClientDeviceWindow*>(); + const GfxCmdWindowReshape& upload = stream.ReadValueType<GfxCmdWindowReshape>(); + handle->GetInternal()->Reshape(upload.width, upload.height, upload.depthFormat, upload.antiAlias); + Signal(); + break; + } + case kGfxCmd_WindowDestroy: + { + ClientDeviceWindow* handle = stream.ReadValueType<ClientDeviceWindow*>(); + delete handle->GetInternal(); + Signal(); + break; + } + case kGfxCmd_BeginRendering: + { + ClientDeviceWindow* handle = stream.ReadValueType<ClientDeviceWindow*>(); + handle->GetInternal()->BeginRendering(); + break; + } + case kGfxCmd_EndRendering: + { + ClientDeviceWindow* handle = stream.ReadValueType<ClientDeviceWindow*>(); + bool presentContent = stream.ReadValueType<GfxCmdBool>(); + handle->GetInternal()->EndRendering(presentContent); + GfxCmdBool signalEvent = stream.ReadValueType<GfxCmdBool>(); + if (signalEvent) + SignalEvent(kEventTypePresent); + break; + } +#endif + case kGfxCmd_AcquireThreadOwnership: + { + m_Device->AcquireThreadOwnership(); + SetRealGfxDeviceThreadOwnership(); + Signal(); + m_IsThreadOwner = true; + break; + } + case kGfxCmd_ReleaseThreadOwnership: + { + m_Device->ReleaseThreadOwnership(); + Signal(); + m_IsThreadOwner = false; + break; + } + + #if ENABLE_PROFILER + case kGfxCmd_BeginProfileEvent: + { + const char* name = stream.ReadValueType<const char*>(); + m_Device->BeginProfileEvent (name); + break; + } + case kGfxCmd_EndProfileEvent: + { + m_Device->EndProfileEvent (); + break; + } + case kGfxCmd_ProfileControl: + { + GfxDevice::GfxProfileControl ctrl = stream.ReadValueType<GfxDevice::GfxProfileControl>(); + unsigned param = stream.ReadValueType<unsigned>(); + + #if ENABLE_PROFILER + switch (ctrl) + { + case GfxDevice::kGfxProfBeginFrame: profiler_begin_frame_seperate_thread((ProfilerMode)param); break; + case GfxDevice::kGfxProfEndFrame: profiler_end_frame_seperate_thread(param); break; + case GfxDevice::kGfxProfDisableSampling: profiler_disable_sampling_seperate_thread(); break; + case GfxDevice::kGfxProfSetActive: profiler_set_active_seperate_thread(param!=0); break; + } + #else + AssertString("shouldn't be invoked"); + #endif + break; + } + case kGfxCmd_BeginTimerQueries: + { + PROFILER_AUTO(gMTBeginQueriesProf, NULL); + m_Device->BeginTimerQueries(); + // Implicitly poll queries + PollTimerQueries(); + break; + } + case kGfxCmd_EndTimerQueries: + { + PROFILER_AUTO(gMTEndQueriesProf, NULL); + m_Device->EndTimerQueries(); + stream.ReadReleaseData(); + break; + } + case kGfxCmd_TimerQuery_Constructor: + { + ClientDeviceTimerQuery* query = stream.ReadValueType<ClientDeviceTimerQuery*>(); + query->internalQuery = m_Device->CreateTimerQuery(); + break; + } + case kGfxCmd_TimerQuery_Destructor: + { + ClientDeviceTimerQuery* query = stream.ReadValueType<ClientDeviceTimerQuery*>(); + m_Device->DeleteTimerQuery(query->GetInternal()); + break; + } + case kGfxCmd_TimerQuery_Measure: + { + ClientDeviceTimerQuery* query = stream.ReadValueType<ClientDeviceTimerQuery*>(); + if (query->GetInternal()) + { + Assert(!query->pending); + query->pending = true; + query->GetInternal()->Measure(); + m_PolledTimerQueries.push_back(query); + } + break; + } + case kGfxCmd_TimerQuery_GetElapsed: + { + ClientDeviceTimerQuery* query = stream.ReadValueType<ClientDeviceTimerQuery*>(); + UInt32 flags = stream.ReadValueType<UInt32>(); + bool wait = (flags & GfxTimerQuery::kWaitRenderThread) != 0; + while (query->pending) + PollNextTimerQuery(wait); + if (flags & GfxTimerQuery::kWaitClientThread) + Signal(); + break; + } + #endif + + case kGfxCmd_DeleteGPUSkinningInfo: + { + GPUSkinningInfo *info = stream.ReadValueType<GPUSkinningInfo *>(); + m_Device->DeleteGPUSkinningInfo(info); + break; + } + case kGfxCmd_SkinOnGPU: + { + #if ENABLE_GFXDEVICE_REMOTE_PROCESS + // todo. + #else + GPUSkinningInfo *info = stream.ReadValueType<GPUSkinningInfo *>(); + ClientDeviceVBO* destVBO = stream.ReadValueType<ClientDeviceVBO*>(); + bool lastThisFrame = stream.ReadValueType<bool>(); + info->SetDestVBO(destVBO->GetInternal()); + + m_Device->SkinOnGPU(info, lastThisFrame); + #endif + break; + } + + case kGfxCmd_UpdateSkinSourceData: + { + GPUSkinningInfo *info = stream.ReadValueType<GPUSkinningInfo *>(); + void *vboData = stream.ReadValueType<void *>(); + BoneInfluence *bones = stream.ReadValueType<BoneInfluence *>(); + bool dirty = stream.ReadValueType<bool>(); + + m_Device->UpdateSkinSourceData(info, vboData, bones, dirty); + + break; + } + + case kGfxCmd_UpdateSkinBonePoses: + { + GPUSkinningInfo *info = stream.ReadValueType<GPUSkinningInfo *>(); + int boneSize = stream.ReadValueType<int>(); + Matrix4x4f *bones = stream.ReadArrayType<Matrix4x4f>(boneSize); + + m_Device->UpdateSkinBonePoses(info, boneSize, bones); + + break; + } + +#if UNITY_XENON + case kGfxCmd_RawVBO_Constructor: + { + ClientDeviceRawVBO* vbo = stream.ReadValueType<ClientDeviceRawVBO*>(); + UInt32 size = stream.ReadValueType<UInt32>(); + UInt32 flags = stream.ReadValueType<UInt32>(); + vbo->internalVBO = m_Device->CreateRawVBO(size, flags); + break; + } + case kGfxCmd_RawVBO_Destructor: + { + ClientDeviceRawVBO* vbo = stream.ReadValueType<ClientDeviceRawVBO*>(); + m_Device->DeleteRawVBO(vbo->GetInternal()); + delete vbo; + break; + } + case kGfxCmd_RawVBO_Next: + { + ClientDeviceRawVBO* vbo = stream.ReadValueType<ClientDeviceRawVBO*>(); + vbo->GetInternal()->Next(); + break; + } + case kGfxCmd_RawVBO_Write: + { + ClientDeviceRawVBO* vbo = stream.ReadValueType<ClientDeviceRawVBO*>(); + UInt32 offset = stream.ReadValueType<UInt32>(); + UInt32 size = stream.ReadValueType<UInt32>(); + void* dest = vbo->GetInternal()->GetMemory(offset, size); + stream.ReadStreamingData(dest, size); + break; + } + case kGfxCmd_RawVBO_InvalidateGpuCache: + { + ClientDeviceRawVBO* vbo = stream.ReadValueType<ClientDeviceRawVBO*>(); + vbo->GetInternal()->InvalidateGpuCache(); + break; + } + case kGfxCmd_EnablePersistDisplayOnQuit: + { + bool enabled = stream.ReadValueType<bool>(); + m_Device->EnablePersistDisplayOnQuit(enabled); + break; + } + case kGfxCmd_RegisterTexture2D: + { + TextureID tid = stream.ReadValueType<TextureID>(); + IDirect3DBaseTexture9* tex = stream.ReadValueType<IDirect3DBaseTexture9*>(); + m_Device->RegisterTexture2D(tid, tex); + break; + } + case kGfxCmd_PatchTexture2D: + { + TextureID tid = stream.ReadValueType<TextureID>(); + IDirect3DBaseTexture9* tex = stream.ReadValueType<IDirect3DBaseTexture9*>(); + m_Device->PatchTexture2D(tid, tex); + break; + } + case kGfxCmd_DeleteTextureEntryOnly: + { + TextureID tid = stream.ReadValueType<TextureID>(); + m_Device->DeleteTextureEntryOnly(tid); + break; + } + case kGfxCmd_UnbindAndDelayReleaseTexture: + { + IDirect3DBaseTexture9* tex = stream.ReadValueType<IDirect3DBaseTexture9*>(); + m_Device->UnbindAndDelayReleaseTexture(tex); + break; + } + case kGfxCmd_SetTextureWrapModes: + { + TextureID tid = stream.ReadValueType<TextureID>(); + TextureWrapMode wrapU = stream.ReadValueType<TextureWrapMode>(); + TextureWrapMode wrapV = stream.ReadValueType<TextureWrapMode>(); + TextureWrapMode wrapW = stream.ReadValueType<TextureWrapMode>(); + m_Device->SetTextureWrapModes(tid, wrapU, wrapV, wrapW); + break; + } + case kGfxCmd_OnLastFrameCallback: + { + m_Device->OnLastFrameCallback(); + break; + } + case kGfxCmd_VideoPlayer_Constructor: + { + ClientDeviceVideoPlayer* vp = stream.ReadValueType<ClientDeviceVideoPlayer*>(); + bool fullscreen = stream.ReadValueType<bool>(); + vp->internalVP = m_Device->CreateVideoPlayer(fullscreen); + break; + } + case kGfxCmd_VideoPlayer_Destructor: + { + ClientDeviceVideoPlayer* vp = stream.ReadValueType<ClientDeviceVideoPlayer*>(); + m_Device->DeleteVideoPlayer(vp->GetInternal()); + delete vp; + break; + } + case kGfxCmd_VideoPlayer_Render: + { + ClientDeviceVideoPlayer* vp = stream.ReadValueType<ClientDeviceVideoPlayer*>(); + vp->GetInternal()->Render(); + vp->isDead = vp->GetInternal()->IsDead(); + break; + } + case kGfxCmd_VideoPlayer_Pause: + { + ClientDeviceVideoPlayer* vp = stream.ReadValueType<ClientDeviceVideoPlayer*>(); + vp->GetInternal()->Pause(); + break; + } + case kGfxCmd_VideoPlayer_Resume: + { + ClientDeviceVideoPlayer* vp = stream.ReadValueType<ClientDeviceVideoPlayer*>(); + vp->GetInternal()->Resume(); + break; + } + case kGfxCmd_VideoPlayer_Stop: + { + ClientDeviceVideoPlayer* vp = stream.ReadValueType<ClientDeviceVideoPlayer*>(); + vp->GetInternal()->Stop(); + break; + } + case kGfxCmd_VideoPlayer_SetPlaySpeed: + { + ClientDeviceVideoPlayer* vp = stream.ReadValueType<ClientDeviceVideoPlayer*>(); + float speed = stream.ReadValueType<float>(); + vp->GetInternal()->SetPlaySpeed(speed); + break; + } + case kGfxCmd_VideoPlayer_Play: + { + ClientDeviceVideoPlayer* vp = stream.ReadValueType<ClientDeviceVideoPlayer*>(); + XMEDIA_XMV_CREATE_PARAMETERS xmvParams = stream.ReadValueType<XMEDIA_XMV_CREATE_PARAMETERS>(); + bool loop = stream.ReadValueType<bool>(); + if (xmvParams.createType == XMEDIA_CREATE_FROM_FILE) + { + size_t len = stream.ReadValueType<size_t>(); + char* fileName = (char*)_alloca(len); + stream.ReadStreamingData(fileName, len); + xmvParams.createFromFile.szFileName = fileName; + } + bool hasRect = stream.ReadValueType<bool>(); + RECT rect; + RECT* rectPtr = 0; + if (hasRect) + { + rect = stream.ReadValueType<RECT>(); + rectPtr = ▭ + } + vp->GetInternal()->Play(xmvParams, loop, rectPtr); + break; + } + case kGfxCmd_SetNullPixelShader: + { + m_Device->SetNullPixelShader(); + break; + } + case kGfxCmd_EnableHiZ: + { + HiZstate hiz_enable = stream.ReadValueType<HiZstate>(); + m_Device->SetHiZEnable( hiz_enable ); + break; + } + case kGfxCmd_SetHiStencilState: + { + bool hiStencilEnable = stream.ReadValueType<bool>(); + bool hiStencilWriteEnable = stream.ReadValueType<bool>(); + int hiStencilRef = stream.ReadValueType<int>(); + CompareFunction cmpFunc = stream.ReadValueType<CompareFunction>(); + + Assert( hiStencilRef < 256 ); + Assert( cmpFunc == kFuncEqual || cmpFunc == kFuncNotEqual ); + m_Device->SetHiStencilState( hiStencilEnable, hiStencilWriteEnable, hiStencilRef, cmpFunc ); + break; + } + case kGfxCmd_HiStencilFlush: + { + HiSflush flushtype = stream.ReadValueType<HiSflush>(); + m_Device->HiStencilFlush( flushtype ); + break; + } +#endif // UNITY_XENON + default: + ErrorString(Format("Gfx command not handled: %d (Last command: %d)", cmd, lastCmd)); + } + + GFXDEVICE_LOCKSTEP_WORKER(); + lastCmd = cmd; +} + +void GfxDeviceWorker::DoLockstep(int pos, int cmd) +{ + if (m_CallDepth == 0) + { + //printf_console("MT: worker pos %i cmd %i\n", pos, cmd); + m_LockstepSemaphore.Signal(); + } +} + +UInt8* GfxDeviceWorker::ReadBufferData (ThreadedStreamBuffer& stream, int size) +{ + int maxNonStreamedSize = stream.GetAllocatedSize() / 2; + if (size <= maxNonStreamedSize || m_CallDepth > 0) + { + stream.ReadReleaseData(); + void* data = stream.GetReadDataPointer(size, ThreadedStreamBuffer::kDefaultAlignment); + return reinterpret_cast<UInt8*>(data); + } + else + { + m_TempBuffer.resize_uninitialized(size); + stream.ReadStreamingData(m_TempBuffer.data(), size); + return m_TempBuffer.data(); + } +} + +void GfxDeviceWorker::WritebackData (ThreadedStreamBuffer& stream, const void* data, int size) +{ + const SInt32 maxSize = m_CommandQueue->ReadValueType<SInt32>(); + SInt32 writtenSize = 0; + do + { + void* chunkPtr = m_CommandQueue->GetReadDataPointer(sizeof(SInt32) + maxSize, ThreadedStreamBuffer::kDefaultAlignment); + SInt32* returnedSizePtr = static_cast<SInt32*>(chunkPtr); + void* returnedDataPtr = &returnedSizePtr[1]; + SInt32 chunkSize = std::min<SInt32>(size, maxSize); + if (chunkSize > 0) + memcpy(returnedDataPtr, static_cast<const UInt8*>(data) + writtenSize, chunkSize); + UnityMemoryBarrier(); + *returnedSizePtr = chunkSize; + stream.ReadReleaseData(); + writtenSize += size; + } while (writtenSize < size); +} + +#if ENABLE_PROFILER +void GfxDeviceWorker::PollTimerQueries() +{ + for (;;) + { + if (!PollNextTimerQuery(false)) + break; + } +} + +bool GfxDeviceWorker::PollNextTimerQuery(bool wait) +{ + if (m_PolledTimerQueries.empty()) + return false; + + ClientDeviceTimerQuery* query = m_PolledTimerQueries.front(); + UInt32 flags = wait ? GfxTimerQuery::kWaitAll : 0; + ProfileTimeFormat elapsed = query->GetInternal()->GetElapsed(flags); + if (elapsed != kInvalidProfileTime) + { + m_PolledTimerQueries.pop_front(); + // Make result available to client thread + query->elapsed = elapsed; + UnityMemoryBarrier(); + query->pending = false; + return true; + } + return false; +} +#endif + +#endif diff --git a/Runtime/GfxDevice/threaded/GfxDeviceWorker.h b/Runtime/GfxDevice/threaded/GfxDeviceWorker.h new file mode 100644 index 0000000..4129917 --- /dev/null +++ b/Runtime/GfxDevice/threaded/GfxDeviceWorker.h @@ -0,0 +1,135 @@ +#pragma once +#if ENABLE_MULTITHREADED_CODE + +#include "Runtime/GfxDevice/GfxDevice.h" +#include "Runtime/GfxDevice/threaded/WorkerIDMapper.h" +#include "Runtime/Utilities/dynamic_array.h" +#include "Runtime/Shaders/VBO.h" +#include "Runtime/Threads/Mutex.h" +#include "Runtime/Threads/Semaphore.h" +#include "Runtime/Threads/JobScheduler.h" +#include "External/shaderlab/Library/TextureBinding.h" +#include "Runtime/Filters/Mesh/MeshSkinning.h" +#include <deque> + + +#define GFXDEVICE_USE_CACHED_STATE 0 +#define DEBUG_GFXDEVICE_LOCKSTEP 0 + +#if DEBUG_GFXDEVICE_LOCKSTEP + #define GFXDEVICE_LOCKSTEP_CLIENT() { DoLockstep(); } + #define GFXDEVICE_LOCKSTEP_WORKER() { DoLockstep(pos, cmd); } +#else + #define GFXDEVICE_LOCKSTEP_CLIENT() + #define GFXDEVICE_LOCKSTEP_WORKER() +#endif + +struct ClientDeviceTimerQuery; +class ThreadedStreamBuffer; +class ThreadedDisplayList; +class Thread; + +class GfxDeviceWorker : public NonCopyable +{ +public: + GfxDeviceWorker(int maxCallDepth, ThreadedStreamBuffer* commandQueue); + ~GfxDeviceWorker(); + + GfxThreadableDevice* Startup(GfxDeviceRenderer renderer, bool threaded, bool forceRef); + + void WaitForSignal(); + void LockstepWait(); + + void GetLastFrameStats(GfxDeviceStats& stats); + + void CallImmediate(ThreadedDisplayList* dlist); + + enum EventType + { + kEventTypePresent, + kEventTypeTimerQueries, + kEventTypeCount + }; + + void WaitForEvent(EventType type); + + void WaitOnCPUFence(UInt32 fence); + + bool DidPresentFrame(UInt32 frameID) const; + + bool RunCommandIfDataIsAvailable(); + +private: + void SignalEvent(EventType type); + + static void* RunGfxDeviceWorker(void *data); + + void Run(); + void RunCommand(ThreadedStreamBuffer& stream); + void Signal(); + void DoLockstep(int pos, int cmd); + + UInt8* ReadBufferData(ThreadedStreamBuffer& stream, int size); + void WritebackData(ThreadedStreamBuffer& stream, const void* data, int size); + +#if ENABLE_PROFILER + void PollTimerQueries(); + bool PollNextTimerQuery(bool wait); +#endif + +#if GFXDEVICE_USE_CACHED_STATE + struct CachedState + { + CachedState(); + NormalizationMode normalization; + int backface; + Vector4f ambient; + int fogEnabled; + GfxFogParams fogParams; + }; +#endif + + int m_CallDepth; + int m_MaxCallDepth; + Thread* m_WorkerThread; + ThreadedStreamBuffer* m_CommandQueue; + ThreadedStreamBuffer* m_MainCommandQueue; + ThreadedStreamBuffer* m_PlaybackCommandQueues; + ThreadedDisplayList** m_PlaybackDisplayLists; + dynamic_array<UInt8> m_TempBuffer; + dynamic_array<SkinMeshInfo> m_ActiveSkins; + dynamic_array<VBO*> m_MappedSkinVBOs; + JobScheduler::JobGroupID m_SkinJobGroup; + Semaphore m_EventSemaphores[kEventTypeCount]; + Semaphore m_LockstepSemaphore; + Semaphore m_WaitSemaphore; + volatile UInt32 m_CurrentCPUFence; + volatile UInt32 m_PresentFrameID; + Mutex m_StatsMutex; + GfxDeviceStats m_FrameStats; + GfxThreadableDevice* m_Device; + bool m_IsThreadOwner; + bool m_Quit; +#if GFXDEVICE_USE_CACHED_STATE + CachedState m_Cached; +#endif +#if ENABLE_PROFILER + // Timer queries for GPU profiling + typedef std::deque<ClientDeviceTimerQuery*> TimerQueryList; + TimerQueryList m_PolledTimerQueries; +#endif +#if ENABLE_GFXDEVICE_REMOTE_PROCESS + WorkerIDMapper<DeviceBlendState> m_BlendStateMapper; + WorkerIDMapper<DeviceDepthState> m_DepthStateMapper; + WorkerIDMapper<DeviceStencilState> m_StencilStateMapper; + WorkerIDMapper<DeviceRasterState> m_RasterStateMapper; + WorkerIDMapper<VBO> m_VBOMapper; + WorkerIDMapper<void> m_TextureCombinerMapper; + WorkerIDMapper<void> m_RenderSurfaceMapper; + WorkerIDMapper<GpuProgramParameters> m_GpuProgramParametersMapper; + WorkerIDMapper<GpuProgram> m_GpuProgramMapper; + ClientIDMapper m_GpuProgramClientMapper; +#endif +}; + +#endif diff --git a/Runtime/GfxDevice/threaded/GfxReturnStructs.cpp b/Runtime/GfxDevice/threaded/GfxReturnStructs.cpp new file mode 100644 index 0000000..dd90789 --- /dev/null +++ b/Runtime/GfxDevice/threaded/GfxReturnStructs.cpp @@ -0,0 +1,239 @@ +#include "UnityPrefix.h" +#include "GfxReturnStructs.h" +#include "Runtime/GfxDevice/ChannelAssigns.h" + +static int AppendString(dynamic_array<char>& strBuf, const char* str) +{ + int strLen = strlen(str); + int strOfs = strBuf.size(); + strBuf.resize_uninitialized(strOfs + strLen + 1); + std::copy(str, str + strLen + 1, &strBuf[strOfs]); + return strOfs; +} + +static const char* GetStringAtOffset(int offset, const char* strBuf, int strBufLen) +{ + if (offset >= 0 && offset < strBufLen) + return &strBuf[offset]; + ErrorString("Invalid offset in GetStringAtOffset()"); + return ""; +} + +GfxRet_ValueParameter::GfxRet_ValueParameter(const GpuProgramParameters::ValueParameter& src, dynamic_array<char>& strBuf) +: index(src.m_Index) +, arraySize(src.m_ArraySize) +, rowCount(src.m_RowCount) +, colCount(src.m_ColCount) +{ + nameStrOfs = AppendString(strBuf, src.m_Name.GetName()); +} + +void GfxRet_ValueParameter::ToValueParameter(GpuProgramParameters::ValueParameter& dest, const char* strBuf, int strBufLen) const +{ + dest.m_Name = ShaderLab::Property(GetStringAtOffset(nameStrOfs, strBuf, strBufLen)); + dest.m_Index = index; + dest.m_ArraySize = arraySize; + dest.m_RowCount = rowCount; + dest.m_ColCount = colCount; +} + + +GfxRet_TextureParameter::GfxRet_TextureParameter(const GpuProgramParameters::TextureParameter& src, dynamic_array<char>& strBuf) +: index(src.m_Index) +, samplerIndex(src.m_SamplerIndex) +, dim(src.m_Dim) +{ + nameStrOfs = AppendString(strBuf, src.m_Name.GetName()); +} + +void GfxRet_TextureParameter::ToTextureParameter(GpuProgramParameters::TextureParameter& dest, const char* strBuf, int strBufLen) const +{ + dest.m_Name = ShaderLab::Property(GetStringAtOffset(nameStrOfs, strBuf, strBufLen)); + dest.m_Index = index; + dest.m_SamplerIndex = samplerIndex; + dest.m_Dim = dim; +} + + +GfxRet_BufferParameter::GfxRet_BufferParameter(const GpuProgramParameters::BufferParameter& src, dynamic_array<char>& strBuf) +: index(src.m_Index) +{ + nameStrOfs = AppendString(strBuf, src.m_Name.GetName()); +} + +void GfxRet_BufferParameter::ToBufferParameter(GpuProgramParameters::BufferParameter& dest, const char* strBuf, int strBufLen) const +{ + dest.m_Name = ShaderLab::Property(GetStringAtOffset(nameStrOfs, strBuf, strBufLen)); + dest.m_Index = index; +} + +GfxRet_ShaderError::GfxRet_ShaderError(const ShaderErrors::ShaderError& src, dynamic_array<char>& strBuf) +: line(src.line) +, warning(src.warning) +, programError(src.programError) +{ + messageStrOfs = AppendString(strBuf, src.message.c_str()); + messageDetailsStrOfs = AppendString(strBuf, src.messageDetails.c_str()); +} + +void GfxRet_ShaderError::ToShaderError(ShaderErrors::ShaderError& dest, const char* strBuf, int strBufLen) const +{ + dest.message = GetStringAtOffset(messageStrOfs, strBuf, strBufLen); + dest.messageDetails = GetStringAtOffset(messageDetailsStrOfs, strBuf, strBufLen); + dest.line = line; + dest.warning = warning; + dest.programError = programError; +} + + +GfxRet_ChannelAssigns::GfxRet_ChannelAssigns(const ChannelAssigns& src) +: targetMap(src.m_TargetMap) +, sourceMap(src.m_SourceMap) +, directlyWired(src.m_DirectlyWired) +{ + std::copy(src.m_Channels, src.m_Channels + kVertexCompCount, channels); +}; + +void GfxRet_ChannelAssigns::ToChannelAssigns(ChannelAssigns& dest) const +{ + dest.m_TargetMap = targetMap; + dest.m_SourceMap = sourceMap; + dest.m_DirectlyWired = directlyWired; + std::copy(channels, channels + kVertexCompCount, dest.m_Channels); +} + +Gfx_GpuProgramParameters::Gfx_GpuProgramParameters() +: valueParameterCount(0) +, valueParameterOffset(0) +, textureParameterCount(0) +, textureParameterOffset(0) +, bufferParameterCount(0) +, bufferParameterOffset(0) +{ +} + +Gfx_GpuProgramParameters::Gfx_GpuProgramParameters(const GpuProgramParameters& params, dynamic_array<UInt8>& outBuf, dynamic_array<char> &strBuf) +{ + const GpuProgramParameters::ValueParameterArray& srcValueParams = params.GetValueParams(); + valueParameterCount = srcValueParams.size(); + valueParameterOffset = outBuf.size(); + outBuf.resize_uninitialized(valueParameterOffset + valueParameterCount * sizeof(GfxRet_ValueParameter)); + GfxRet_ValueParameter* valueParams = reinterpret_cast<GfxRet_ValueParameter*>(outBuf.data() + valueParameterOffset); + for (int i = 0; i < valueParameterCount; ++i) + valueParams[i] = GfxRet_ValueParameter(srcValueParams[i], strBuf); + + const GpuProgramParameters::TextureParameterList& srcTextureParams = params.GetTextureParams(); + textureParameterCount = srcTextureParams.size(); + textureParameterOffset = outBuf.size(); + outBuf.resize_uninitialized(textureParameterOffset + textureParameterCount * sizeof(GfxRet_TextureParameter)); + GfxRet_TextureParameter* textureParams = reinterpret_cast<GfxRet_TextureParameter*>(outBuf.data() + textureParameterOffset); + for (int i = 0; i < textureParameterCount; ++i) + textureParams[i] = GfxRet_TextureParameter(srcTextureParams[i], strBuf); + + const GpuProgramParameters::BufferParameterArray& srcBufferParams = params.GetBufferParams(); + bufferParameterCount = srcBufferParams.size(); + bufferParameterOffset = outBuf.size(); + outBuf.resize_uninitialized(bufferParameterOffset + bufferParameterCount * sizeof(GfxRet_BufferParameter)); + GfxRet_BufferParameter* bufferParams = reinterpret_cast<GfxRet_BufferParameter*>(outBuf.data() + bufferParameterOffset); + for (int i = 0; i < bufferParameterCount; ++i) + bufferParams[i] = GfxRet_BufferParameter(srcBufferParams[i], strBuf); +} + +void Gfx_GpuProgramParameters::GetOutput(GpuProgramParameters& outParams, const char* dataBegin, const char* stringBuffer, int stringBufferLength) const +{ + const GfxRet_ValueParameter* valueParams = reinterpret_cast<const GfxRet_ValueParameter*>(dataBegin + valueParameterOffset); + for (int i = 0; i < valueParameterCount; ++i) + { + GpuProgramParameters::ValueParameter param; + valueParams[i].ToValueParameter(param, stringBuffer, stringBufferLength); + outParams.AddValueParam(param); + } + + const GfxRet_TextureParameter* textureParams = reinterpret_cast<const GfxRet_TextureParameter*>(dataBegin + textureParameterOffset); + for (int i = 0; i < textureParameterCount; ++i) + { + GpuProgramParameters::TextureParameter param; + textureParams[i].ToTextureParameter(param, stringBuffer, stringBufferLength); + outParams.AddTextureParam(param); + } +} + +GfxRet_CreateGpuProgram::GfxRet_CreateGpuProgram(const CreateGpuProgramOutput& output, dynamic_array<UInt8>& outBuf) +: channelAssignsCount(0) +, channelAssignsOffset(0) +, shaderErrorCount(0) +, shaderErrorOffset(0) +, stringBufferLength(0) +, stringBufferOffset(0) +{ + perFogModeParamsEnabled = output.GetPerFogModeParamsEnabled(); + + // Shared buffer for strings + dynamic_array<char> strBuf; + + if (output.GetParams()) + { + params = Gfx_GpuProgramParameters(*output.GetParams(), outBuf, strBuf); + } + + if (output.GetChannelAssigns()) + { + channelAssignsCount = 1; + channelAssignsOffset = outBuf.size(); + outBuf.resize_uninitialized(channelAssignsOffset + channelAssignsCount * sizeof(GfxRet_ChannelAssigns)); + GfxRet_ChannelAssigns* channelAssigns = reinterpret_cast<GfxRet_ChannelAssigns*>(outBuf.data() + channelAssignsOffset); + channelAssigns[0] = GfxRet_ChannelAssigns(*output.GetChannelAssigns()); + } + + if (output.GetShaderErrors()) + { + const ShaderErrors::ErrorContainer& srcShaderErrors = output.GetShaderErrors()->GetErrors(); + shaderErrorCount = srcShaderErrors.size(); + shaderErrorOffset = outBuf.size(); + outBuf.resize_uninitialized(shaderErrorOffset + shaderErrorCount * sizeof(GfxRet_ShaderError)); + GfxRet_ShaderError* shaderErrors = reinterpret_cast<GfxRet_ShaderError*>(outBuf.data() + shaderErrorOffset); + ShaderErrors::ErrorContainer::const_iterator srcIt = srcShaderErrors.begin(); + for (int i = 0; i < shaderErrorCount; ++srcIt, ++i) + new (shaderErrors + i) GfxRet_ShaderError(*srcIt, strBuf); + Assert(srcIt == srcShaderErrors.end()); + } + + stringBufferLength = strBuf.size(); + stringBufferOffset = outBuf.size(); + outBuf.resize_uninitialized(stringBufferOffset + stringBufferLength); + std::copy(strBuf.begin(), strBuf.end(), outBuf.begin() + stringBufferOffset); +} + +void GfxRet_CreateGpuProgram::GetOutput(CreateGpuProgramOutput& output) const +{ + output.SetPerFogModeParamsEnabled(perFogModeParamsEnabled); + + const char* dataBegin = reinterpret_cast<const char*>(this); + const char* stringBuffer = dataBegin + stringBufferOffset; + + if (params.valueParameterCount > 0 || params.textureParameterCount > 0 || params.bufferParameterCount > 0) + { + GpuProgramParameters& outParams = output.CreateParams(); + params.GetOutput(outParams, dataBegin, stringBuffer, stringBufferLength); + } + + if (channelAssignsCount > 0) + { + Assert(channelAssignsCount == 1); + const GfxRet_ChannelAssigns* channelAssigns = reinterpret_cast<const GfxRet_ChannelAssigns*>(dataBegin + channelAssignsOffset); + channelAssigns[0].ToChannelAssigns(output.CreateChannelAssigns()); + } + + if (shaderErrorCount > 0) + { + ShaderErrors& outErrors = output.CreateShaderErrors(); + + const GfxRet_ShaderError* shaderErrors = reinterpret_cast<const GfxRet_ShaderError*>(dataBegin + shaderErrorOffset); + for (int i = 0; i < shaderErrorCount; ++i) + { + ShaderErrors::ShaderError err; + shaderErrors[i].ToShaderError(err, stringBuffer, stringBufferLength); + outErrors.AddShaderError(err.message, err.messageDetails, err.line, err.warning, err.programError); + } + } +} diff --git a/Runtime/GfxDevice/threaded/GfxReturnStructs.h b/Runtime/GfxDevice/threaded/GfxReturnStructs.h new file mode 100644 index 0000000..f3e7b47 --- /dev/null +++ b/Runtime/GfxDevice/threaded/GfxReturnStructs.h @@ -0,0 +1,122 @@ +#pragma once + +#include "Runtime/GfxDevice/GpuProgram.h" +#include "Runtime/Utilities/dynamic_array.h" +#include "External/shaderlab/Library/ShaderLabErrors.h" +class ChannelAssigns; +namespace ShaderLab { class SubProgram; } + +struct GfxRet_ValueParameter +{ + GfxRet_ValueParameter(const GpuProgramParameters::ValueParameter& src, dynamic_array<char>& strBuf); + void ToValueParameter(GpuProgramParameters::ValueParameter& dest, const char* strBuf, int strBufLen) const; + + int nameStrOfs; + int index; + int arraySize; + UInt8 rowCount; + UInt8 colCount; +}; + +struct GfxRet_TextureParameter +{ + GfxRet_TextureParameter(const GpuProgramParameters::TextureParameter& src, dynamic_array<char>& strBuf); + void ToTextureParameter(GpuProgramParameters::TextureParameter& dest, const char* strBuf, int strBufLen) const; + + int nameStrOfs; + int index; + int samplerIndex; + TextureDimension dim; +}; + +struct GfxRet_BufferParameter +{ + GfxRet_BufferParameter(const GpuProgramParameters::BufferParameter& src, dynamic_array<char>& strBuf); + void ToBufferParameter(GpuProgramParameters::BufferParameter& dest, const char* strBuf, int strBufLen) const; + + int nameStrOfs; + int index; +}; + +struct GfxRet_ChannelAssigns +{ + GfxRet_ChannelAssigns(const ChannelAssigns& src); + void ToChannelAssigns(ChannelAssigns& dest) const; + + UInt32 targetMap; + UInt32 sourceMap; + SInt8 channels[kVertexCompCount]; + bool directlyWired; +}; + +struct GfxRet_ShaderError +{ + GfxRet_ShaderError(const ShaderErrors::ShaderError& src, dynamic_array<char>& strBuf); + void ToShaderError(ShaderErrors::ShaderError& dest, const char* strBuf, int strBufLen) const; + + int messageStrOfs; + int messageDetailsStrOfs; + int line; + bool warning; + bool programError; +}; + +struct Gfx_GpuProgramParameters +{ + Gfx_GpuProgramParameters(); + Gfx_GpuProgramParameters(const GpuProgramParameters& params, dynamic_array<UInt8>& outBuf, dynamic_array<char> &strBuf); + + //void GetOutput(GpuProgramParameters &output, const char* strBuf, int strBufLen) const; + void GetOutput(GpuProgramParameters& outParams, const char* dataBegin, const char* strBuf, int strBufLen) const; + + int valueParameterCount; + int valueParameterOffset; + + // Array of GfxRet_TextureParameter + int textureParameterCount; + int textureParameterOffset; + + // Array of GfxRet_BufferParameter + int bufferParameterCount; + int bufferParameterOffset; +}; + +struct GfxRet_CreateGpuProgram +{ + GfxRet_CreateGpuProgram(const CreateGpuProgramOutput& output, dynamic_array<UInt8>& outBuf); + + void GetOutput(CreateGpuProgramOutput& output) const; + + bool perFogModeParamsEnabled; + + Gfx_GpuProgramParameters params; + /* + // Array of GfxRet_ValueParameter + int valueParameterCount; + int valueParameterOffset; + + // Array of GfxRet_TextureParameter + int textureParameterCount; + int textureParameterOffset; + + // Array of GfxRet_BufferParameter + int bufferParameterCount; + int bufferParameterOffset; + */ + // Array of GfxRet_ChannelAssigns + int channelAssignsCount; + int channelAssignsOffset; + + // Array of GfxRet_ShaderError + int shaderErrorCount; + int shaderErrorOffset; + + // Shared buffer of string data + int stringBufferLength; + int stringBufferOffset; + + ClientIDMapper::ClientID gpuProgram; + + PropertyNamesSet names; +}; + diff --git a/Runtime/GfxDevice/threaded/ThreadedDeviceStates.h b/Runtime/GfxDevice/threaded/ThreadedDeviceStates.h new file mode 100644 index 0000000..a36a2fa --- /dev/null +++ b/Runtime/GfxDevice/threaded/ThreadedDeviceStates.h @@ -0,0 +1,134 @@ +#pragma once +#if ENABLE_MULTITHREADED_CODE + +#include "Runtime/GfxDevice/GfxDeviceObjects.h" +#include "Runtime/GfxDevice/GfxDeviceResources.h" +#include "Runtime/GfxDevice/threaded/ClientIDMapper.h" +#include "Runtime/Filters/Mesh/VertexData.h" +#include "Runtime/Graphics/RenderSurface.h" + +namespace ShaderLab { struct TextureBinding; } +namespace xenon { class IVideoPlayer; } +class VBO; +class RawVBO; +class GfxTimerQuery; +class GfxDeviceWindow; + +struct ClientDeviceRect +{ + ClientDeviceRect() : x(0), y(0), width(0), height(0) {} + int x; + int y; + int width; + int height; +}; + +struct ClientDeviceBlendState : public DeviceBlendState +{ + ClientDeviceBlendState(const GfxBlendState& src) : DeviceBlendState(src), internalState(NULL) {} + ClientIDWrapper(DeviceBlendState) internalState; +}; + +struct ClientDeviceDepthState : public DeviceDepthState +{ + ClientDeviceDepthState(const GfxDepthState& src) : DeviceDepthState(src), internalState(NULL) {} + ClientIDWrapper(DeviceDepthState) internalState; +}; + +struct ClientDeviceStencilState : public DeviceStencilState +{ + ClientDeviceStencilState(const GfxStencilState& src) : DeviceStencilState(src), internalState(NULL) {} + ClientIDWrapper(DeviceStencilState) internalState; +}; + +struct ClientDeviceRasterState : public DeviceRasterState +{ + ClientDeviceRasterState(const GfxRasterState& src) : DeviceRasterState(src), internalState(NULL) {} + ClientIDWrapper(DeviceRasterState) internalState; +}; + +struct ClientDeviceTextureCombiners +{ + ClientIDWrapperHandle(TextureCombinersHandle) internalHandle; + ShaderLab::TextureBinding* bindings; + int count; +}; + +struct ClientDeviceRenderSurface : RenderSurfaceBase +{ + enum SurfaceState { kInitial, kCleared, kRendered, kResolved }; + ClientDeviceRenderSurface(int w, int h) { RenderSurfaceBase_Init(*this); width=w; height=h; zformat=kDepthFormatNone; state=kInitial; } + ClientIDWrapperHandle(RenderSurfaceHandle) internalHandle; + DepthBufferFormat zformat; + SurfaceState state; +}; + +struct ClientDeviceVBO +{ + ClientDeviceVBO() : internalVBO(NULL) {} + +#if ENABLE_GFXDEVICE_REMOTE_PROCESS + ClientIDWrapper(VBO) GetInternal() { return internalVBO; } +#else + VBO* GetInternal() { return const_cast<VBO*>(internalVBO); } +#endif + volatile ClientIDWrapper(VBO) internalVBO; +}; + +struct ClientVertexBufferData +{ + ChannelInfoArray channels; + StreamInfoArray streams; + int bufferSize; + int vertexCount; + int hasData; +}; + +struct ClientDeviceTimerQuery +{ + ClientDeviceTimerQuery() : internalQuery(NULL), elapsed(0), pending(false) {} + GfxTimerQuery* GetInternal() { return const_cast<GfxTimerQuery*>(internalQuery); } + volatile GfxTimerQuery* internalQuery; + volatile UInt64 elapsed; + volatile bool pending; +}; + +struct ClientDeviceWindow +{ + ClientDeviceWindow() : internalWindow(NULL) {} + GfxDeviceWindow* GetInternal() { return const_cast<GfxDeviceWindow*>(internalWindow); } + volatile GfxDeviceWindow* internalWindow; +}; + +struct ClientDeviceConstantBuffer +{ + ClientDeviceConstantBuffer(UInt32 sz) : size(sz) {} + ConstantBufferHandle internalHandle; + UInt32 size; +}; + +struct ClientDeviceComputeProgram +{ + ClientDeviceComputeProgram() {} + ComputeProgramHandle internalHandle; +}; + + +#if UNITY_XENON +struct ClientDeviceRawVBO +{ + ClientDeviceRawVBO() : internalVBO(NULL) {} + RawVBO* GetInternal() { return const_cast<RawVBO*>(internalVBO); } + volatile RawVBO* internalVBO; +}; + +struct ClientDeviceVideoPlayer +{ + ClientDeviceVideoPlayer() : internalVP(NULL), isDead(false) {} + xenon::IVideoPlayer* GetInternal() { return const_cast<xenon::IVideoPlayer*>(internalVP); } + volatile xenon::IVideoPlayer* internalVP; + volatile bool isDead; +}; +#endif + +#endif diff --git a/Runtime/GfxDevice/threaded/ThreadedDisplayList.cpp b/Runtime/GfxDevice/threaded/ThreadedDisplayList.cpp new file mode 100644 index 0000000..27fa38e --- /dev/null +++ b/Runtime/GfxDevice/threaded/ThreadedDisplayList.cpp @@ -0,0 +1,442 @@ +#include "UnityPrefix.h" + +#if ENABLE_MULTITHREADED_CODE + +#define DEBUG_GPU_PARAMETER_PATCHING (!UNITY_RELEASE) + +#include "Runtime/GfxDevice/threaded/ThreadedDisplayList.h" +#include "Runtime/GfxDevice/threaded/GfxDeviceClient.h" +#include "Runtime/GfxDevice/threaded/GfxDeviceWorker.h" +#include "Runtime/GfxDevice/threaded/GfxCommands.h" +#include "Runtime/Threads/ThreadedStreamBuffer.h" +#include "External/shaderlab/Library/properties.h" +#include "External/shaderlab/Library/shaderlab.h" + +DisplayListContext::DisplayListContext() +{ + ClearState(); +} + +void DisplayListContext::ClearState() +{ + recordFailed = false; + hasSetShaders = false; + memset(shadersActive, 0, sizeof(shadersActive)); + fogParamsOffset = kFogParamsNone; +} + +void DisplayListContext::Reset() +{ + ClearState(); + commandQueue.ResetGrowable(); + patchInfo.Reset(); +} + + +ThreadedDisplayList::ThreadedDisplayList(const void* data, size_t size, const DisplayListContext& context) + : m_ListData(data, size, context.patchInfo) +{ + m_HasSetShaders = context.hasSetShaders; + memcpy(m_ShadersActive, context.shadersActive, sizeof(m_ShadersActive)); + + if (context.fogParamsOffset >= 0) + m_FogParamsOffset = CopyClientData(context.fogParamsOffset, sizeof(GfxFogParams)); + else + m_FogParamsOffset = context.fogParamsOffset; +} + +ThreadedDisplayList::~ThreadedDisplayList() +{ +} + +void ThreadedDisplayList::Call() +{ + GfxDeviceClient& device = (GfxDeviceClient&)GetGfxDevice(); + if (device.IsSerializing()) + { + ThreadedStreamBuffer& queue = *device.GetCommandQueue(); + AddRef(); // Release again when call is finished + queue.WriteValueType<GfxCommand>(kGfxCmd_DisplayList_Call); + queue.WriteValueType<ThreadedDisplayList*>(this); + m_ListData.WriteParameters(queue); + GFXDEVICE_LOCKSTEP_CLIENT(); + } + else + { + m_ListData.PatchImmediate(); + device.GetGfxDeviceWorker()->CallImmediate(this); + } + UpdateClientDevice(device); +} + +void ThreadedDisplayList::Patch(ThreadedStreamBuffer& queue) +{ + m_ListData.Patch(queue); +} + +int ThreadedDisplayList::CopyClientData(int offset, int size) +{ + int newOffset = m_ClientData.AppendData(&m_ListData.m_Buffer[offset], size); + int relativeOffset = newOffset - offset; + for (int pt = 0; pt < GfxPatch::kTypeCount; pt++) + { + GfxPatch::Type patchType = GfxPatch::Type(pt); + int patchCount = m_ListData.m_PatchInfo.GetPatchCount(patchType); + for (int i = 0; i < patchCount; i++) + { + const GfxPatch& srcPatch = m_ListData.m_PatchInfo.GetPatch(patchType, i); + int patchOffset = srcPatch.patchOffset; + if (patchOffset >= offset && patchOffset < offset + size) + { + GfxPatch patch = srcPatch; + patch.patchOffset += relativeOffset; + m_ClientData.m_PatchInfo.AddPatch(patchType, patch); + } + } + } + return newOffset; +} + +void ThreadedDisplayList::UpdateClientDevice(GfxDeviceClient& device) +{ + if (!m_ClientData.m_Buffer.empty()) + m_ClientData.PatchImmediate(); + + if (m_FogParamsOffset != DisplayListContext::kFogParamsNone) + { + if (m_FogParamsOffset != DisplayListContext::kFogParamsDisable) + { + const void* data = &m_ClientData.m_Buffer[m_FogParamsOffset]; + const GfxFogParams& fogParams = *static_cast<const GfxFogParams*>(data); + device.UpdateFogEnabled(fogParams); + } + else + device.UpdateFogDisabled(); + } + + if (m_HasSetShaders) + device.UpdateShadersActive(m_ShadersActive); +} + +void ThreadedDisplayList::DoLockstep() +{ + GfxDeviceClient& device = (GfxDeviceClient&)GetGfxDevice(); + device.DoLockstep(); +} + +ThreadedDisplayList::PatchableData::PatchableData(const void* data, size_t size, const GfxPatchInfo& patchInfo) + : m_PatchInfo(patchInfo) +{ + m_Buffer.resize_uninitialized(size); + memcpy(m_Buffer.begin(), data, size); +} + +ThreadedDisplayList::PatchableData::PatchableData() +{ +} + +void ThreadedDisplayList::PatchableData::CheckParametersValid() +{ +#if DEBUG_GPU_PARAMETER_PATCHING + BuiltinShaderParamValues& builtinParams = GetGfxDevice().GetBuiltinParamValues(); + using namespace ShaderLab; + + FastPropertyName name; + size_t floatCount = m_PatchInfo.GetPatchCount(GfxPatch::kTypeFloat); + for (size_t i = 0; i < floatCount; i++) + { + const GfxPatch& patch = m_PatchInfo.GetPatch(GfxPatch::kTypeFloat, i); + const float* src = reinterpret_cast<const float*>(patch.source); + name.index = patch.nameIndex; + if (name.IsBuiltin()) + { + Assert(name.IsBuiltinVector()); + const float& val = *builtinParams.GetVectorParam(BuiltinShaderVectorParam(name.BuiltinIndex())).GetPtr(); + Assert(&val == src); + } + else + { + const float& val = g_GlobalProperties->GetFloat(name); + Assert(src == NULL || &val == src); + } + } + + size_t vectorCount = m_PatchInfo.GetPatchCount(GfxPatch::kTypeVector); + for (size_t i = 0; i < vectorCount; i++) + { + const GfxPatch& patch = m_PatchInfo.GetPatch(GfxPatch::kTypeVector, i); + const Vector4f* src = reinterpret_cast<const Vector4f*>(patch.source); + name.index = patch.nameIndex; + if (name.IsBuiltin()) + { + Assert(name.IsBuiltinVector()); + const Vector4f& vec = builtinParams.GetVectorParam(BuiltinShaderVectorParam(name.BuiltinIndex())); + Assert(&vec == src); + } + else + { + const Vector4f& vec = g_GlobalProperties->GetVector(name); + Assert(src == NULL || &vec == src); + } + } + + size_t matrixCount = m_PatchInfo.GetPatchCount(GfxPatch::kTypeMatrix); + for (size_t i = 0; i < matrixCount; i++) + { + const GfxPatch& patch = m_PatchInfo.GetPatch(GfxPatch::kTypeMatrix, i); + const Matrix4x4f* src = reinterpret_cast<const Matrix4x4f*>(patch.source); + name.index = patch.nameIndex; + if (name.IsBuiltin()) + { + Assert(name.IsBuiltinMatrix()); + const Matrix4x4f* mat = &builtinParams.GetMatrixParam(BuiltinShaderMatrixParam(name.BuiltinIndex())); + Assert(mat == src); + } + else + { + int count = 0; + const Matrix4x4f* mat = reinterpret_cast<const Matrix4x4f*>(g_GlobalProperties->GetValueProp (name, &count)); + Assert (src == NULL || mat == src); + } + } + + const size_t bufferCount = m_PatchInfo.GetPatchCount(GfxPatch::kTypeBuffer); + for (size_t i = 0; i < bufferCount; i++) + { + const GfxPatch& patch = m_PatchInfo.GetPatch(GfxPatch::kTypeBuffer, i); + const ComputeBufferID* src = reinterpret_cast<const ComputeBufferID*>(patch.source); + name.index = patch.nameIndex; + Assert (!name.IsBuiltin()); + const ComputeBufferID& buf = g_GlobalProperties->GetComputeBuffer(name); + Assert(src == NULL || &buf == src); + } +#endif +} + +void ThreadedDisplayList::PatchableData::WriteParameters(ThreadedStreamBuffer& queue) +{ + CheckParametersValid(); + + size_t floatCount = m_PatchInfo.GetPatchCount(GfxPatch::kTypeFloat); + for (size_t i = 0; i < floatCount; i++) + { + const GfxPatch& patch = m_PatchInfo.GetPatch(GfxPatch::kTypeFloat, i); + float* dest = queue.GetWritePointer<float>(); + PatchFloat(patch, dest); + } + + size_t vectorCount = m_PatchInfo.GetPatchCount(GfxPatch::kTypeVector); + for (size_t i = 0; i < vectorCount; i++) + { + const GfxPatch& patch = m_PatchInfo.GetPatch(GfxPatch::kTypeVector, i); + Vector4f* dest = queue.GetWritePointer<Vector4f>(); + PatchVector(patch, dest); + } + + size_t matrixCount = m_PatchInfo.GetPatchCount(GfxPatch::kTypeMatrix); + for (size_t i = 0; i < matrixCount; i++) + { + const GfxPatch& patch = m_PatchInfo.GetPatch(GfxPatch::kTypeMatrix, i); + Matrix4x4f* dest = queue.GetWritePointer<Matrix4x4f>(); + PatchMatrix(patch, dest); + } + + size_t texEnvCount = m_PatchInfo.GetTexEnvPatchCount(); + for (size_t i = 0; i < texEnvCount; i++) + { + const GfxTexEnvPatch& patch = m_PatchInfo.GetTexEnvPatch(i); + if (patch.patchFlags & GfxTexEnvPatch::kPatchProperties) + { + TexEnvProperties* dest = queue.GetWritePointer<TexEnvProperties>(); + PatchTexEnvProperties(patch, dest); + } + if (patch.patchFlags & GfxTexEnvPatch::kPatchMatrix) + { + Matrix4x4f* dest = queue.GetWritePointer<Matrix4x4f>(); + PatchTexEnvMatrix(patch, dest); + } + } + + const size_t bufferCount = m_PatchInfo.GetPatchCount(GfxPatch::kTypeBuffer); + for (size_t i = 0; i < bufferCount; i++) + { + const GfxPatch& patch = m_PatchInfo.GetPatch(GfxPatch::kTypeBuffer, i); + ComputeBufferID* dest = queue.GetWritePointer<ComputeBufferID>(); + PatchBuffer(patch, dest); + } +} + +void ThreadedDisplayList::PatchableData::PatchImmediate() +{ + CheckParametersValid(); + + size_t floatCount = m_PatchInfo.GetPatchCount(GfxPatch::kTypeFloat); + for (size_t i = 0; i < floatCount; i++) + { + const GfxPatch& patch = m_PatchInfo.GetPatch(GfxPatch::kTypeFloat, i); + float* dest = reinterpret_cast<float*>(&m_Buffer[patch.patchOffset]); + PatchFloat(patch, dest); + } + + size_t vectorCount = m_PatchInfo.GetPatchCount(GfxPatch::kTypeVector); + for (size_t i = 0; i < vectorCount; i++) + { + const GfxPatch& patch = m_PatchInfo.GetPatch(GfxPatch::kTypeVector, i); + Vector4f* dest = reinterpret_cast<Vector4f*>(&m_Buffer[patch.patchOffset]); + PatchVector(patch, dest); + } + + size_t matrixCount = m_PatchInfo.GetPatchCount(GfxPatch::kTypeMatrix); + for (size_t i = 0; i < matrixCount; i++) + { + const GfxPatch& patch = m_PatchInfo.GetPatch(GfxPatch::kTypeMatrix, i); + Matrix4x4f* dest = reinterpret_cast<Matrix4x4f*>(&m_Buffer[patch.patchOffset]); + PatchMatrix(patch, dest); + } + + size_t texEnvCount = m_PatchInfo.GetTexEnvPatchCount(); + for (size_t i = 0; i < texEnvCount; i++) + { + const GfxTexEnvPatch& patch = m_PatchInfo.GetTexEnvPatch(i); + TexEnvData* dest = reinterpret_cast<TexEnvData*>(&m_Buffer[patch.patchOffset]); + + if (patch.patchFlags & GfxTexEnvPatch::kPatchProperties) + PatchTexEnvProperties(patch, dest); + + if (patch.patchFlags & GfxTexEnvPatch::kPatchMatrix) + PatchTexEnvMatrix(patch, &dest->matrix); + } + + size_t bufferCount = m_PatchInfo.GetPatchCount(GfxPatch::kTypeBuffer); + for (size_t i = 0; i < bufferCount; i++) + { + const GfxPatch& patch = m_PatchInfo.GetPatch(GfxPatch::kTypeBuffer, i); + ComputeBufferID* dest = reinterpret_cast<ComputeBufferID*>(&m_Buffer[patch.patchOffset]); + PatchBuffer(patch, dest); + } +} + +void ThreadedDisplayList::PatchableData::Patch(ThreadedStreamBuffer& queue) +{ + FastPropertyName name; + + size_t floatCount = m_PatchInfo.GetPatchCount(GfxPatch::kTypeFloat); + for (size_t i = 0; i < floatCount; i++) + { + const GfxPatch& patch = m_PatchInfo.GetPatch(GfxPatch::kTypeFloat, i); + float val = queue.ReadValueType<float>(); + *reinterpret_cast<float*>(&m_Buffer[patch.patchOffset]) = val; + } + + size_t vectorCount = m_PatchInfo.GetPatchCount(GfxPatch::kTypeVector); + for (size_t i = 0; i < vectorCount; i++) + { + const GfxPatch& patch = m_PatchInfo.GetPatch(GfxPatch::kTypeVector, i); + const Vector4f& vec = queue.ReadValueType<Vector4f>(); + *reinterpret_cast<Vector4f*>(&m_Buffer[patch.patchOffset]) = vec; + } + + size_t matrixCount = m_PatchInfo.GetPatchCount(GfxPatch::kTypeMatrix); + for (size_t i = 0; i < matrixCount; i++) + { + const GfxPatch& patch = m_PatchInfo.GetPatch(GfxPatch::kTypeMatrix, i); + const Matrix4x4f& mat = queue.ReadValueType<Matrix4x4f>(); + *reinterpret_cast<Matrix4x4f*>(&m_Buffer[patch.patchOffset]) = mat; + } + + size_t texEnvCount = m_PatchInfo.GetTexEnvPatchCount(); + for (size_t i = 0; i < texEnvCount; i++) + { + using namespace ShaderLab; + const GfxTexEnvPatch& patch = m_PatchInfo.GetTexEnvPatch(i); + TexEnvData& data = *reinterpret_cast<TexEnvData*>(&m_Buffer[patch.patchOffset]); + if (patch.patchFlags & GfxTexEnvPatch::kPatchProperties) + { + TexEnvProperties& dest = data; + // Patch doesn't know if matrix is identity + // Fortunately we can just keep the old value + bool savedIdentityMatrix = dest.identityMatrix; + dest = queue.ReadValueType<TexEnvProperties>(); + dest.identityMatrix = savedIdentityMatrix; + } + if (patch.patchFlags & GfxTexEnvPatch::kPatchMatrix) + data.matrix = queue.ReadValueType<Matrix4x4f>(); + } + + const size_t bufferCount = m_PatchInfo.GetPatchCount(GfxPatch::kTypeBuffer); + for (size_t i = 0; i < bufferCount; i++) + { + const GfxPatch& patch = m_PatchInfo.GetPatch(GfxPatch::kTypeBuffer, i); + const ComputeBufferID& buf = queue.ReadValueType<ComputeBufferID>(); + *reinterpret_cast<ComputeBufferID*>(&m_Buffer[patch.patchOffset]) = buf; + } +} + +void ThreadedDisplayList::PatchableData::PatchFloat(const GfxPatch& patch, float* dest) +{ + using namespace ShaderLab; + FastPropertyName name; + name.index = patch.nameIndex; + DebugAssert(patch.source || (name.IsValid() && !name.IsBuiltin())); + const float* src = static_cast<const float*>(patch.source); + *dest = src ? *src : g_GlobalProperties->GetFloat(name); +} + +void ThreadedDisplayList::PatchableData::PatchVector(const GfxPatch& patch, Vector4f* dest) +{ + using namespace ShaderLab; + FastPropertyName name; + name.index = patch.nameIndex; + DebugAssert(patch.source || (name.IsValid() && !name.IsBuiltin())); + const Vector4f* src = static_cast<const Vector4f*>(patch.source); + *dest = src ? *src : g_GlobalProperties->GetVector(name); +} + +void ThreadedDisplayList::PatchableData::PatchMatrix(const GfxPatch& patch, Matrix4x4f* dest) +{ + using namespace ShaderLab; + FastPropertyName name; + name.index = patch.nameIndex; + DebugAssert(patch.source || (name.IsValid() && !name.IsBuiltin())); + const Matrix4x4f* src = static_cast<const Matrix4x4f*>(patch.source); + if (!src) + { + int count = 0; + src = reinterpret_cast<const Matrix4x4f*>(g_GlobalProperties->GetValueProp (name, &count)); + if (count < 16) + src = NULL; + } + *dest = src ? *src : Matrix4x4f::identity; +} + +void ThreadedDisplayList::PatchableData::PatchBuffer(const GfxPatch& patch, ComputeBufferID* dest) +{ + using namespace ShaderLab; + FastPropertyName name; + name.index = patch.nameIndex; + DebugAssert(patch.source || (name.IsValid() && !name.IsBuiltin())); + const ComputeBufferID* src = static_cast<const ComputeBufferID*>(patch.source); + *dest = src ? *src : g_GlobalProperties->GetComputeBuffer(name); +} + +void ThreadedDisplayList::PatchableData::PatchTexEnvProperties(const GfxTexEnvPatch& patch, TexEnvProperties* dest) +{ + patch.texEnv->PrepareProperties(patch.nameIndex, dest); +} + +void ThreadedDisplayList::PatchableData::PatchTexEnvMatrix(const GfxTexEnvPatch& patch, Matrix4x4f* dest) +{ + bool identity; + patch.texEnv->PrepareMatrix(patch.matrixName, ShaderLab::g_GlobalProperties, dest, identity); +} + +int ThreadedDisplayList::PatchableData::AppendData(const void* data, int size) +{ + int offset = m_Buffer.size(); + m_Buffer.resize_uninitialized(offset + size); + memcpy(&m_Buffer[offset], data, size); + return offset; +} + + +#endif diff --git a/Runtime/GfxDevice/threaded/ThreadedDisplayList.h b/Runtime/GfxDevice/threaded/ThreadedDisplayList.h new file mode 100644 index 0000000..5711f8e --- /dev/null +++ b/Runtime/GfxDevice/threaded/ThreadedDisplayList.h @@ -0,0 +1,85 @@ +#ifndef THREADED_DISPLAY_LIST_H +#define THREADED_DISPLAY_LIST_H + +#if ENABLE_MULTITHREADED_CODE + +#include "Runtime/Threads/ThreadedStreamBuffer.h" +#include "Runtime/GfxDevice/GfxDisplayList.h" +#include "Runtime/GfxDevice/GfxPatchInfo.h" +#include "Runtime/GfxDevice/GpuProgram.h" + +class GfxDeviceClient; + +struct DisplayListContext +{ + DisplayListContext(); + void ClearState(); + void Reset(); + + enum + { + kFogParamsNone = -1, + kFogParamsDisable = -2 + }; + + ThreadedStreamBuffer commandQueue; + GfxPatchInfo patchInfo; + bool recordFailed; + bool hasSetShaders; + bool shadersActive[kShaderTypeCount]; + int fogParamsOffset; +}; + + +class ThreadedDisplayList : public GfxDisplayList +{ +public: + ThreadedDisplayList(const void* data, size_t size, const DisplayListContext& context); + ~ThreadedDisplayList(); + + void Call(); + + UInt8* GetData() { return m_ListData.m_Buffer.begin(); } + const UInt8* GetData() const { return m_ListData.m_Buffer.begin(); } + size_t GetSize() const { return m_ListData.m_Buffer.size(); } + + void Patch(ThreadedStreamBuffer& queue); + +private: + int CopyClientData(int offset, int size); + void UpdateClientDevice(GfxDeviceClient& device); + void DoLockstep(); + + class PatchableData + { + public: + PatchableData(const void* data, size_t size, + const GfxPatchInfo& patchInfo); + PatchableData(); + + void CheckParametersValid(); + void WriteParameters(ThreadedStreamBuffer& queue); + void PatchImmediate(); + void Patch(ThreadedStreamBuffer& queue); + void PatchFloat(const GfxPatch& patch, float* dest); + void PatchVector(const GfxPatch& patch, Vector4f* dest); + void PatchMatrix(const GfxPatch& patch, Matrix4x4f* dest); + void PatchBuffer(const GfxPatch& patch, ComputeBufferID* dest); + void PatchTexEnvProperties(const GfxTexEnvPatch& patch, TexEnvProperties* dest); + void PatchTexEnvMatrix(const GfxTexEnvPatch& patch, Matrix4x4f* dest); + int AppendData(const void* data, int size); + + dynamic_array<UInt8> m_Buffer; + GfxPatchInfo m_PatchInfo; + }; + + PatchableData m_ListData; + PatchableData m_ClientData; + bool m_HasSetShaders; + bool m_ShadersActive[kShaderTypeCount]; + int m_FogParamsOffset; +}; + + +#endif +#endif diff --git a/Runtime/GfxDevice/threaded/ThreadedTimerQuery.cpp b/Runtime/GfxDevice/threaded/ThreadedTimerQuery.cpp new file mode 100644 index 0000000..2b1731a --- /dev/null +++ b/Runtime/GfxDevice/threaded/ThreadedTimerQuery.cpp @@ -0,0 +1,102 @@ +#include "UnityPrefix.h" +#if ENABLE_PROFILER +#include "ThreadedTimerQuery.h" +#include "GfxDeviceWorker.h" +#include "Runtime/Threads/ThreadUtility.h" +#include "Runtime/Threads/ThreadedStreamBuffer.h" +#include "Runtime/GfxDevice/threaded/GfxDeviceClient.h" +#include "Runtime/GfxDevice/threaded/GfxCommands.h" + +ThreadedTimerQuery::ThreadedTimerQuery(GfxDeviceClient& device) +: m_ClientDevice(device) +{ + m_ClientQuery = new ClientDeviceTimerQuery; + DebugAssert(Thread::CurrentThreadIsMainThread()); + if (m_ClientDevice.IsSerializing()) + { + ThreadedStreamBuffer& stream = *m_ClientDevice.GetCommandQueue(); + stream.WriteValueType<GfxCommand>(kGfxCmd_TimerQuery_Constructor); + stream.WriteValueType<ClientDeviceTimerQuery*>(m_ClientQuery); + GFXDEVICE_LOCKSTEP_CLIENT(); + } + else + m_ClientQuery->internalQuery = GetRealGfxDevice().CreateTimerQuery(); +} + +ThreadedTimerQuery::~ThreadedTimerQuery() +{ + DebugAssert(Thread::CurrentThreadIsMainThread()); + if (m_ClientDevice.IsSerializing()) + { + ThreadedStreamBuffer& stream = *m_ClientDevice.GetCommandQueue(); + stream.WriteValueType<GfxCommand>(kGfxCmd_TimerQuery_Destructor); + stream.WriteValueType<ClientDeviceTimerQuery*>(m_ClientQuery); + GFXDEVICE_LOCKSTEP_CLIENT(); + } + else + { + Assert(m_ClientQuery); + GetRealGfxDevice().DeleteTimerQuery(m_ClientQuery->GetInternal()); + delete m_ClientQuery; + } + m_ClientQuery = NULL; +} + +void ThreadedTimerQuery::Measure() +{ + DebugAssert(Thread::CurrentThreadIsMainThread()); + if (m_ClientDevice.IsSerializing()) + { + ThreadedStreamBuffer& stream = *m_ClientDevice.GetCommandQueue(); + stream.WriteValueType<GfxCommand>(kGfxCmd_TimerQuery_Measure); + stream.WriteValueType<ClientDeviceTimerQuery*>(m_ClientQuery); + GFXDEVICE_LOCKSTEP_CLIENT(); + } + else + m_ClientQuery->GetInternal()->Measure(); +} + +ProfileTimeFormat ThreadedTimerQuery::GetElapsed(UInt32 flags) +{ + DebugAssert(Thread::CurrentThreadIsMainThread()); + if (m_ClientDevice.IsSerializing()) + { + // See if we have the result already + ProfileTimeFormat time = GetElapsedIfReady(); + if (time != kInvalidProfileTime) + return time; + + // Request result from worker thread + ThreadedStreamBuffer& stream = *m_ClientDevice.GetCommandQueue(); + stream.WriteValueType<GfxCommand>(kGfxCmd_TimerQuery_GetElapsed); + stream.WriteValueType<ClientDeviceTimerQuery*>(m_ClientQuery); + stream.WriteValueType<UInt32>(flags); + if (flags & GfxTimerQuery::kWaitClientThread) + { + m_ClientDevice.SubmitCommands(); + m_ClientDevice.GetGfxDeviceWorker()->WaitForSignal(); + } + GFXDEVICE_LOCKSTEP_CLIENT(); + return GetElapsedIfReady(); + } + else + return m_ClientQuery->GetInternal()->GetElapsed(flags); +} + +ProfileTimeFormat ThreadedTimerQuery::GetElapsedIfReady() +{ + if (!m_ClientQuery->pending) + { + // Be careful since UInt64 isn't guaranteed atomic + UnityMemoryBarrier(); + return m_ClientQuery->elapsed; + } + return kInvalidProfileTime; +} + +void ThreadedTimerQuery::DoLockstep() +{ + m_ClientDevice.DoLockstep(); +} + +#endif diff --git a/Runtime/GfxDevice/threaded/ThreadedTimerQuery.h b/Runtime/GfxDevice/threaded/ThreadedTimerQuery.h new file mode 100644 index 0000000..b8aecbd --- /dev/null +++ b/Runtime/GfxDevice/threaded/ThreadedTimerQuery.h @@ -0,0 +1,29 @@ +#ifndef THREADEDTIMERQUERY_H +#define THREADEDTIMERQUERY_H + +#if ENABLE_PROFILER + +#include "Runtime/GfxDevice/GfxTimerQuery.h" + +class GfxDeviceClient; +struct ClientDeviceTimerQuery; + +class ThreadedTimerQuery : public GfxTimerQuery +{ +public: + ThreadedTimerQuery(GfxDeviceClient& device); + ~ThreadedTimerQuery(); + + virtual void Measure(); + virtual ProfileTimeFormat GetElapsed(UInt32 flags); + +private: + ProfileTimeFormat GetElapsedIfReady(); + void DoLockstep(); + + GfxDeviceClient& m_ClientDevice; + ClientDeviceTimerQuery* m_ClientQuery; +}; + +#endif +#endif diff --git a/Runtime/GfxDevice/threaded/ThreadedVBO.cpp b/Runtime/GfxDevice/threaded/ThreadedVBO.cpp new file mode 100644 index 0000000..09fdd5f --- /dev/null +++ b/Runtime/GfxDevice/threaded/ThreadedVBO.cpp @@ -0,0 +1,511 @@ +#include "UnityPrefix.h" +#include "ThreadedVBO.h" +#include "Runtime/Threads/ThreadedStreamBuffer.h" +#include "Runtime/GfxDevice/threaded/GfxDeviceClient.h" +#include "Runtime/GfxDevice/threaded/GfxDeviceWorker.h" +#include "Runtime/GfxDevice/threaded/GfxCommands.h" +#include "Runtime/GfxDevice/ChannelAssigns.h" + + +ThreadedVBO::ThreadedVBO(GfxDeviceClient& device) : + m_ClientDevice(device), + m_ClientVBO(NULL), + m_NonThreadedVBO(NULL), + m_MappedFromRenderThread(false), + m_VertexBufferLost(false), + m_IndexBufferLost(false), + m_VertexBufferSize(0), + m_IndexBufferSize(0) +{ + SET_ALLOC_OWNER(NULL); + DebugAssert(Thread::CurrentThreadIsMainThread()); + m_ClientVBO = UNITY_NEW(ClientDeviceVBO, kMemGfxThread); + if (device.IsThreaded()) + { + + GetCommandQueue().WriteValueType<GfxCommand>(kGfxCmd_VBO_Constructor); +#if ENABLE_GFXDEVICE_REMOTE_PROCESS + m_ClientVBO->internalVBO = m_ClientDevice.m_VBOMapper.CreateID(); + GetCommandQueue().WriteValueType<ClientDeviceVBO>(*m_ClientVBO); +#else + GetCommandQueue().WriteValueType<ClientDeviceVBO*>(m_ClientVBO); +#endif + GetCommandQueue().WriteSubmitData(); + GFXDEVICE_LOCKSTEP_CLIENT(); + } +#if !ENABLE_GFXDEVICE_REMOTE_PROCESS + else + { + m_NonThreadedVBO = GetRealGfxDevice().CreateVBO(); + m_ClientVBO->internalVBO = m_NonThreadedVBO; + } +#endif +} + +ThreadedVBO::~ThreadedVBO() +{ + DebugAssert(Thread::CurrentThreadIsMainThread()); + DebugAssert(!m_ClientDevice.IsRecording()); + if (m_ClientDevice.IsThreaded()) + { + DebugAssert(!m_NonThreadedVBO); + // m_ClientVBO deleted by server + GetCommandQueue().WriteValueType<GfxCommand>(kGfxCmd_VBO_Destructor); +#if ENABLE_GFXDEVICE_REMOTE_PROCESS + GetCommandQueue().WriteValueType<ClientDeviceVBO>(*m_ClientVBO); +#else + GetCommandQueue().WriteValueType<ClientDeviceVBO*>(m_ClientVBO); +#endif + GFXDEVICE_LOCKSTEP_CLIENT(); + } + else + { + DebugAssert(m_NonThreadedVBO); + GetRealGfxDevice().DeleteVBO(m_NonThreadedVBO); + UNITY_DELETE(m_ClientVBO, kMemGfxThread); + } + m_NonThreadedVBO = NULL; + m_ClientVBO = NULL; +} + +void ThreadedVBO::UpdateVertexData( const VertexBufferData& buffer ) +{ + DebugAssert(Thread::CurrentThreadIsMainThread()); + if (m_ClientDevice.IsSerializing()) + { + GetCommandQueue().WriteValueType<GfxCommand>(kGfxCmd_VBO_UpdateVertexData); +#if ENABLE_GFXDEVICE_REMOTE_PROCESS + GetCommandQueue().WriteValueType<ClientDeviceVBO>(*m_ClientVBO); + ClientVertexBufferData client; + memcpy (client.channels, buffer.channels, sizeof(ChannelInfoArray)); + memcpy (client.streams, buffer.streams, sizeof(StreamInfoArray)); + client.bufferSize = buffer.bufferSize; + client.vertexCount = buffer.vertexCount; + client.hasData = buffer.buffer != NULL; + GetCommandQueue().WriteValueType<ClientVertexBufferData>(client); +#else + GetCommandQueue().WriteValueType<ClientDeviceVBO*>(m_ClientVBO); + GetCommandQueue().WriteValueType<VertexBufferData>(buffer); +#endif + if (buffer.buffer) + m_ClientDevice.WriteBufferData(buffer.buffer, buffer.bufferSize); + if (m_MappedFromRenderThread) + UnbufferVertexData(); + else + BufferAccessibleVertexData(buffer); + GFXDEVICE_LOCKSTEP_CLIENT(); + } + else + { + DebugAssert(m_NonThreadedVBO); + m_NonThreadedVBO->UpdateVertexData(buffer); + } + m_VertexBufferSize = buffer.bufferSize; + m_VertexBufferLost = false; +} + +void ThreadedVBO::UpdateIndexData (const IndexBufferData& buffer) +{ + DebugAssert(Thread::CurrentThreadIsMainThread()); + if (m_ClientDevice.IsSerializing()) + { + GetCommandQueue().WriteValueType<GfxCommand>(kGfxCmd_VBO_UpdateIndexData); +#if ENABLE_GFXDEVICE_REMOTE_PROCESS + GetCommandQueue().WriteValueType<ClientDeviceVBO>(*m_ClientVBO); +#else + GetCommandQueue().WriteValueType<ClientDeviceVBO*>(m_ClientVBO); +#endif + GetCommandQueue().WriteValueType<int>(buffer.count); + GetCommandQueue().WriteValueType<UInt32>(buffer.hasTopologies); + m_ClientDevice.WriteBufferData(buffer.indices, CalculateIndexBufferSize(buffer)); + GFXDEVICE_LOCKSTEP_CLIENT(); + } + else + { + DebugAssert(m_NonThreadedVBO); + m_NonThreadedVBO->UpdateIndexData(buffer); + } + m_IndexBufferSize = buffer.count * kVBOIndexSize; + m_IndexBufferLost = false; +} + +void ThreadedVBO::DrawVBO (const ChannelAssigns& channels, UInt32 firstIndexByte, UInt32 indexCount, + GfxPrimitiveType topology, UInt32 firstVertex, UInt32 vertexCount ) +{ + DebugAssert(Thread::CurrentThreadIsMainThread()); + m_ClientDevice.BeforeDrawCall(false); + if (m_ClientDevice.IsSerializing()) + { + GetCommandQueue().WriteValueType<GfxCommand>(kGfxCmd_VBO_Draw); +#if ENABLE_GFXDEVICE_REMOTE_PROCESS + GfxCmdVBODraw data = { *m_ClientVBO, channels, firstIndexByte, indexCount, topology, firstVertex, vertexCount }; +#else + GfxCmdVBODraw data = { m_ClientVBO, channels, firstIndexByte, indexCount, topology, firstVertex, vertexCount }; +#endif + GetCommandQueue().WriteValueType<GfxCmdVBODraw>(data); + GetCommandQueue().WriteSubmitData(); + GFXDEVICE_LOCKSTEP_CLIENT(); + } + else + { + DebugAssert(m_NonThreadedVBO); + m_NonThreadedVBO->DrawVBO (channels, firstIndexByte, indexCount, topology, firstVertex, vertexCount); + } +} + +#if GFX_ENABLE_DRAW_CALL_BATCHING +void ThreadedVBO::DrawCustomIndexed( const ChannelAssigns& channels, void* indices, UInt32 indexCount, + GfxPrimitiveType topology, UInt32 vertexRangeBegin, UInt32 vertexRangeEnd, UInt32 drawVertexCount ) +{ + DebugAssert(Thread::CurrentThreadIsMainThread()); + m_ClientDevice.BeforeDrawCall(false); + if (m_ClientDevice.IsSerializing()) + { + //Note: Presuming that indices are of size UInt16! + GetCommandQueue().WriteValueType<GfxCommand>(kGfxCmd_VBO_DrawCustomIndexed); + GfxCmdVBODrawCustomIndexed data = { m_ClientVBO, channels, indexCount, topology, vertexRangeBegin, vertexRangeEnd, drawVertexCount }; + GetCommandQueue().WriteValueType<GfxCmdVBODrawCustomIndexed>(data); + GetCommandQueue().WriteStreamingData(indices, indexCount*kVBOIndexSize); + GFXDEVICE_LOCKSTEP_CLIENT(); + } + else + { + DebugAssert(m_NonThreadedVBO); + m_NonThreadedVBO->DrawCustomIndexed(channels, indices, indexCount, topology, + vertexRangeBegin, vertexRangeEnd, drawVertexCount); + } +} +#endif + +void ThreadedVBO::Recreate() +{ + DebugAssert(Thread::CurrentThreadIsMainThread()); + if (m_ClientDevice.IsSerializing()) + { + GetCommandQueue().WriteValueType<GfxCommand>(kGfxCmd_VBO_Recreate); +#if ENABLE_GFXDEVICE_REMOTE_PROCESS + GetCommandQueue().WriteValueType<ClientDeviceVBO>(*m_ClientVBO); +#else + GetCommandQueue().WriteValueType<ClientDeviceVBO*>(m_ClientVBO); +#endif + GFXDEVICE_LOCKSTEP_CLIENT(); + } + else + { + DebugAssert(m_NonThreadedVBO); + m_NonThreadedVBO->Recreate(); + } +} + +bool ThreadedVBO::MapVertexStream( VertexStreamData& outData, unsigned stream ) +{ + DebugAssert(Thread::CurrentThreadIsMainThread()); + if (m_ClientDevice.IsSerializing()) + { + BufferedVBO::MapVertexStream(outData, stream); + } + else + { + DebugAssert(m_NonThreadedVBO); + m_IsStreamMapped[stream] = m_NonThreadedVBO->MapVertexStream(outData, stream); + } + return m_IsStreamMapped[stream]; +} + +void ThreadedVBO::UnmapVertexStream( unsigned stream ) +{ + DebugAssert(Thread::CurrentThreadIsMainThread()); + if (m_ClientDevice.IsSerializing()) + { + BufferedVBO::UnmapVertexStream(stream); + + // Send modified vertices to render thread + size_t size = CalculateVertexStreamSize(m_VertexData, stream); +#if ENABLE_GFXDEVICE_REMOTE_PROCESS + GfxCmdVBOMapVertexStream map = { *m_ClientVBO, stream, size }; +#else + GfxCmdVBOMapVertexStream map = { m_ClientVBO, stream, size }; +#endif + GetCommandQueue().WriteValueType<GfxCommand>(kGfxCmd_VBO_MapVertexStream); + GetCommandQueue().WriteValueType<GfxCmdVBOMapVertexStream>(map); + GetCommandQueue().WriteStreamingData(GetStreamBuffer(stream), size); + GFXDEVICE_LOCKSTEP_CLIENT(); + } + else + { + DebugAssert(m_NonThreadedVBO); + m_NonThreadedVBO->UnmapVertexStream(stream); + } + m_IsStreamMapped[0] = false; +} + +bool ThreadedVBO::IsVertexBufferLost() const +{ + if (m_NonThreadedVBO) + return m_NonThreadedVBO->IsVertexBufferLost(); + else + return m_VertexBufferLost; +} + +bool ThreadedVBO::IsIndexBufferLost() const +{ + if (m_NonThreadedVBO) + return m_NonThreadedVBO->IsIndexBufferLost(); + else + return m_IndexBufferLost; +} + +void ThreadedVBO::SetMappedFromRenderThread( bool renderThread ) +{ +#if !ENABLE_GFXDEVICE_REMOTE_PROCESS + m_MappedFromRenderThread = renderThread; +#endif +} + +void ThreadedVBO::SetVertexStreamMode( unsigned stream, StreamMode mode ) +{ + DebugAssert(Thread::CurrentThreadIsMainThread()); + if (mode == GetVertexStreamMode(stream)) + return; + VBO::SetVertexStreamMode(stream, mode); + if (m_ClientDevice.IsSerializing()) + { + GetCommandQueue().WriteValueType<GfxCommand>(kGfxCmd_VBO_SetVertexStreamMode); +#if ENABLE_GFXDEVICE_REMOTE_PROCESS + GfxCmdVBOSetVertexStreamMode vsmode = { *m_ClientVBO, stream, mode }; +#else + GfxCmdVBOSetVertexStreamMode vsmode = { m_ClientVBO, stream, mode }; +#endif + GetCommandQueue().WriteValueType<GfxCmdVBOSetVertexStreamMode>(vsmode); + GFXDEVICE_LOCKSTEP_CLIENT(); + } + else + { + DebugAssert(m_NonThreadedVBO); + m_NonThreadedVBO->SetVertexStreamMode(stream, mode); + } +} + +void ThreadedVBO::SetIndicesDynamic(bool dynamic) +{ + DebugAssert(Thread::CurrentThreadIsMainThread()); + if (dynamic == AreIndicesDynamic()) + return; + VBO::SetIndicesDynamic(dynamic); + if (m_ClientDevice.IsSerializing()) + { + GetCommandQueue().WriteValueType<GfxCommand>(kGfxCmd_VBO_SetIndicesDynamic); +#if ENABLE_GFXDEVICE_REMOTE_PROCESS + GfxCmdVBOSetSetIndicesDynamic vsdyn = { *m_ClientVBO, (int)dynamic }; +#else + GfxCmdVBOSetSetIndicesDynamic vsdyn = { m_ClientVBO, (int)dynamic }; +#endif + GetCommandQueue().WriteValueType<GfxCmdVBOSetSetIndicesDynamic>(vsdyn); + GFXDEVICE_LOCKSTEP_CLIENT(); + } + else + { + DebugAssert(m_NonThreadedVBO); + m_NonThreadedVBO->SetIndicesDynamic(dynamic); + } +} + +void ThreadedVBO::ResetDynamicVB() +{ + for (int s = 0; s < kMaxVertexStreams; s++) + { + if (m_StreamModes[s] == kStreamModeDynamic) + m_VertexBufferLost = true; + } +} + +void ThreadedVBO::MarkBuffersLost() +{ + m_VertexBufferLost = m_IndexBufferLost = true; +} + + +int ThreadedVBO::GetRuntimeMemorySize() const +{ + DebugAssert(Thread::CurrentThreadIsMainThread()); + if (m_ClientDevice.IsSerializing()) + { +#if ENABLE_GFXDEVICE_REMOTE_PROCESS + return 0; +#else + return m_ClientVBO->GetInternal()?m_ClientVBO->GetInternal()->GetRuntimeMemorySize():0; +#endif + } + else + { + DebugAssert(m_NonThreadedVBO); + return m_NonThreadedVBO->GetRuntimeMemorySize(); + } +} + +void ThreadedVBO::UseAsStreamOutput() +{ + DebugAssert(Thread::CurrentThreadIsMainThread()); + if (m_ClientDevice.IsSerializing()) + { + GetCommandQueue().WriteValueType<GfxCommand>(kGfxCmd_VBO_UseAsStreamOutput); + GetCommandQueue().WriteValueType<ClientDeviceVBO *>(m_ClientVBO); + GFXDEVICE_LOCKSTEP_CLIENT(); + } + else + { + DebugAssert(m_NonThreadedVBO); + m_NonThreadedVBO->UseAsStreamOutput(); + } + +} + +#if UNITY_XENON +void ThreadedVBO::AddExtraUvChannels( const UInt8* data, UInt32 size, int extraUvCount ) +{ + DebugAssert(Thread::CurrentThreadIsMainThread()); + if (m_ClientDevice.IsSerializing()) + { + GetCommandQueue().WriteValueType<GfxCommand>(kGfxCmd_VBO_AddExtraUvChannels); + GfxCmdVBOAddExtraUvChannels adduv = { m_ClientVBO, size, extraUvCount }; + GetCommandQueue().WriteValueType<GfxCmdVBOAddExtraUvChannels>(adduv); + GetCommandQueue().WriteStreamingData(data, size); + GFXDEVICE_LOCKSTEP_CLIENT(); + } + else + { + DebugAssert(m_NonThreadedVBO); + m_NonThreadedVBO->AddExtraUvChannels(data, size, extraUvCount); + } +} + +void ThreadedVBO::CopyExtraUvChannels( VBO* source ) +{ + DebugAssert(Thread::CurrentThreadIsMainThread()); + DebugAssert(source != NULL); + ThreadedVBO* src = static_cast<ThreadedVBO*>(source); + if (m_ClientDevice.IsSerializing()) + { + GetCommandQueue().WriteValueType<GfxCommand>(kGfxCmd_VBO_CopyExtraUvChannels); + GfxCmdVBOCopyExtraUvChannels copyuv = { m_ClientVBO, src->m_ClientVBO }; + GetCommandQueue().WriteValueType<GfxCmdVBOCopyExtraUvChannels>(copyuv); + GFXDEVICE_LOCKSTEP_CLIENT(); + } + else + { + DebugAssert(m_NonThreadedVBO); + m_NonThreadedVBO->CopyExtraUvChannels(src->m_NonThreadedVBO); + } +} +#endif + +ThreadedStreamBuffer& ThreadedVBO::GetCommandQueue() +{ + return *m_ClientDevice.GetCommandQueue(); +} + +GfxDeviceWorker* ThreadedVBO::GetGfxDeviceWorker() +{ + return m_ClientDevice.GetGfxDeviceWorker(); +} + +void ThreadedVBO::SubmitCommands() +{ + m_ClientDevice.SubmitCommands(); +} + +void ThreadedVBO::DoLockstep() +{ + m_ClientDevice.DoLockstep(); +} + + +ThreadedDynamicVBO::ThreadedDynamicVBO(GfxDeviceClient& device) : + m_ClientDevice(device), + m_ValidChunk(false) +{ +} + +bool ThreadedDynamicVBO::GetChunk( UInt32 shaderChannelMask, UInt32 maxVertices, UInt32 maxIndices, RenderMode renderMode, void** outVB, void** outIB ) +{ + DebugAssert(Thread::CurrentThreadIsMainThread()); + Assert( !m_LendedChunk ); + DebugAssert( outVB != NULL && maxVertices > 0 ); + DebugAssert( + (renderMode == kDrawIndexedTriangles && (outIB != NULL && maxIndices > 0)) || + (renderMode == kDrawIndexedTriangleStrip && (outIB != NULL && maxIndices > 0)) || + (renderMode == kDrawTriangleStrip && (outIB == NULL && maxIndices == 0)) || + (renderMode == kDrawQuads && (outIB == NULL && maxIndices == 0))); + + m_LendedChunk = true; + m_LastChunkShaderChannelMask = shaderChannelMask; + m_LastRenderMode = renderMode; + + m_LastChunkStride = 0; + for( int i = 0; i < kShaderChannelCount; ++i ) { + if( shaderChannelMask & (1<<i) ) + m_LastChunkStride += VBO::GetDefaultChannelByteSize(i); + } + m_LastChunkVertices = maxVertices; + m_LastChunkIndices = maxIndices; + int vertexChunkSize = m_LastChunkStride * maxVertices; + m_ChunkVertices.resize_uninitialized(vertexChunkSize); + m_ChunkIndices.resize_uninitialized(maxIndices); + *outVB = &m_ChunkVertices[0]; + if (outIB) + *outIB = &m_ChunkIndices[0]; + return true; +} + +void ThreadedDynamicVBO::ReleaseChunk( UInt32 actualVertices, UInt32 actualIndices ) +{ + DebugAssert(Thread::CurrentThreadIsMainThread()); + Assert( m_LendedChunk ); + m_LendedChunk = false; + m_ValidChunk = (actualVertices > 0) && (m_LastChunkIndices == 0 || actualIndices > 0); + if (!m_ValidChunk) + return; + Assert(actualVertices <= m_LastChunkVertices); + Assert(actualIndices <= m_LastChunkIndices); + GetCommandQueue().WriteValueType<GfxCommand>(kGfxCmd_DynVBO_Chunk); + GfxCmdDynVboChunk chunk = { m_LastChunkShaderChannelMask, m_LastChunkStride, actualVertices, actualIndices, m_LastRenderMode }; + GetCommandQueue().WriteValueType<GfxCmdDynVboChunk>(chunk); + GetCommandQueue().WriteStreamingData(&m_ChunkVertices[0], actualVertices * m_LastChunkStride); + if (actualIndices > 0) + GetCommandQueue().WriteStreamingData(&m_ChunkIndices[0], actualIndices * kVBOIndexSize); + GetCommandQueue().WriteSubmitData(); + GFXDEVICE_LOCKSTEP_CLIENT(); +} + +void ThreadedDynamicVBO::DrawChunk (const ChannelAssigns& channels) +{ + DebugAssert(Thread::CurrentThreadIsMainThread()); + Assert( !m_LendedChunk ); + if (!m_ValidChunk) + return; + m_ClientDevice.BeforeDrawCall(false); + GetCommandQueue().WriteValueType<GfxCommand>(kGfxCmd_DynVBO_DrawChunk); + GetCommandQueue().WriteValueType<ChannelAssigns>(channels); + GetCommandQueue().WriteSubmitData(); + GFXDEVICE_LOCKSTEP_CLIENT(); +} + +ThreadedStreamBuffer& ThreadedDynamicVBO::GetCommandQueue() +{ + return *m_ClientDevice.GetCommandQueue(); +} + +GfxDeviceWorker* ThreadedDynamicVBO::GetGfxDeviceWorker() +{ + return m_ClientDevice.GetGfxDeviceWorker(); +} + +void ThreadedDynamicVBO::SubmitCommands() +{ + m_ClientDevice.SubmitCommands(); +} + +void ThreadedDynamicVBO::DoLockstep() +{ + m_ClientDevice.DoLockstep(); +} diff --git a/Runtime/GfxDevice/threaded/ThreadedVBO.h b/Runtime/GfxDevice/threaded/ThreadedVBO.h new file mode 100644 index 0000000..89dbeff --- /dev/null +++ b/Runtime/GfxDevice/threaded/ThreadedVBO.h @@ -0,0 +1,104 @@ +#ifndef THREADEDVBO_H +#define THREADEDVBO_H + +#include "Runtime/GfxDevice/GfxDevice.h" +#include "Configuration/UnityConfigure.h" +#include "Runtime/Shaders/BufferedVBO.h" + +class Mutex; +class GfxDeviceClient; +struct ClientDeviceVBO; +class GfxDeviceWorker; +class ThreadedStreamBuffer; + +class ThreadedVBO : public BufferedVBO { +public: + ThreadedVBO(GfxDeviceClient& device); + virtual ~ThreadedVBO(); + + virtual void UpdateVertexData( const VertexBufferData& buffer ); + virtual void UpdateIndexData (const IndexBufferData& buffer); + virtual void DrawVBO (const ChannelAssigns& channels, UInt32 firstIndexByte, UInt32 indexCount, + GfxPrimitiveType topology, UInt32 firstVertex, UInt32 vertexCount ); + #if GFX_ENABLE_DRAW_CALL_BATCHING + virtual void DrawCustomIndexed( const ChannelAssigns& channels, void* indices, UInt32 indexCount, + GfxPrimitiveType topology, UInt32 vertexRangeBegin, UInt32 vertexRangeEnd, UInt32 drawVertexCount ); + #endif + + virtual void Recreate(); + + // For writing directly to VBO. VBO must be filled (UpdateData) + // at least once; and vertex layout + topology from the last fill + // is used. For example, for skinned meshes you have to call + // UpdateData on start and each time layout/topology changes; + // then map,write,unmap for each skinning. + // + // In some situations a vertex buffer might become lost; then you need to do UpdateData + // again before using Map. + virtual bool MapVertexStream( VertexStreamData& outData, unsigned stream ); + virtual void UnmapVertexStream( unsigned stream ); + virtual bool IsVertexBufferLost() const; + virtual bool IsIndexBufferLost() const; + + virtual void SetMappedFromRenderThread( bool renderThread ); + virtual void SetVertexStreamMode( unsigned stream, StreamMode mode ); + virtual void SetIndicesDynamic(bool dynamic); + + virtual void ResetDynamicVB(); + virtual void MarkBuffersLost(); + + virtual int GetRuntimeMemorySize() const; + + virtual void UseAsStreamOutput(); + +#if UNITY_XENON + virtual void AddExtraUvChannels( const UInt8* data, UInt32 size, int extraUvCount ); + virtual void CopyExtraUvChannels( VBO* source ); +#endif + + ClientDeviceVBO* GetClientDeviceVBO() { return m_ClientVBO; } //Todo:any nicer way? + VBO* GetNonThreadedVBO() { return m_NonThreadedVBO; } + +protected: + ThreadedStreamBuffer& GetCommandQueue(); + GfxDeviceWorker* GetGfxDeviceWorker(); + void SubmitCommands(); + void DoLockstep(); + + GfxDeviceClient& m_ClientDevice; + ClientDeviceVBO* m_ClientVBO; + VBO* m_NonThreadedVBO; + int m_VertexBufferSize; + int m_IndexBufferSize; + bool m_MappedFromRenderThread; + bool m_VertexBufferLost; + bool m_IndexBufferLost; +}; + + +class ThreadedDynamicVBO : public DynamicVBO { +public: + ThreadedDynamicVBO(GfxDeviceClient& device); + virtual ~ThreadedDynamicVBO() { } + + virtual bool GetChunk( UInt32 shaderChannelMask, UInt32 maxVertices, UInt32 maxIndices, RenderMode renderMode, void** outVB, void** outIB ); + + virtual void ReleaseChunk( UInt32 actualVertices, UInt32 actualIndices ); + + virtual void DrawChunk (const ChannelAssigns& channels); + +private: + ThreadedStreamBuffer& GetCommandQueue(); + GfxDeviceWorker* GetGfxDeviceWorker(); + void SubmitCommands(); + void DoLockstep(); + + GfxDeviceClient& m_ClientDevice; + ThreadedStreamBuffer* m_CommandQueue; + dynamic_array<UInt8> m_ChunkVertices; + dynamic_array<UInt16> m_ChunkIndices; + bool m_ValidChunk; +}; + + +#endif diff --git a/Runtime/GfxDevice/threaded/ThreadedWindow.cpp b/Runtime/GfxDevice/threaded/ThreadedWindow.cpp new file mode 100644 index 0000000..bab324f --- /dev/null +++ b/Runtime/GfxDevice/threaded/ThreadedWindow.cpp @@ -0,0 +1,97 @@ +#include "UnityPrefix.h" +#include "Runtime/GfxDevice/threaded/ThreadedWindow.h" +#include "Runtime/GfxDevice/threaded/GfxDeviceClient.h" +#include "Runtime/Graphics/RenderTexture.h" +#include "Runtime/Misc/QualitySettings.h" + + +#if UNITY_WIN && UNITY_EDITOR + +int ThreadedWindow::ms_CurrentFSAALevel = 0; + +ThreadedWindow::ThreadedWindow(HWND window, int width, int height, DepthBufferFormat depthFormat, int antiAlias ) +: GfxDeviceWindow(window, width, height, depthFormat, antiAlias) +{ + m_ClientWindow = new ClientDeviceWindow; + m_FSAALevel = antiAlias; + m_Reshaped = false; + + // Creating the actual window calls Reshape on the base class + // Threaded window should be kept in the same state + GfxDeviceWindow::Reshape(width, height, depthFormat, antiAlias); +} + +ThreadedWindow::~ThreadedWindow() +{ + GfxDeviceClient& device = (GfxDeviceClient&)GetGfxDevice(); + device.WindowDestroy(m_ClientWindow); + m_ClientWindow = NULL; +} + +bool ThreadedWindow::Reshape( int width, int height, DepthBufferFormat depthFormat, int antiAlias ) +{ + if(!GfxDeviceWindow::Reshape(width, height, depthFormat, antiAlias)) + return false; + + GfxDeviceClient& device = (GfxDeviceClient&)GetGfxDevice(); + device.WindowReshape(m_ClientWindow, width, height, depthFormat, antiAlias); + m_Reshaped = true; + return true; +} + +void ThreadedWindow::SetAsActiveWindow () +{ + GfxDeviceClient& device = (GfxDeviceClient&)GetGfxDevice(); + device.SetActiveWindow(m_ClientWindow); + OnActivateWindow(); +} + +bool ThreadedWindow::BeginRendering() +{ + if (GfxDeviceWindow::BeginRendering()) + { + GfxDeviceClient& device = (GfxDeviceClient&)GetGfxDevice(); + device.BeginRendering(m_ClientWindow); + OnActivateWindow(); + return true; + } + else + { + return false; + } +} + +bool ThreadedWindow::EndRendering( bool presentContent ) +{ + if(GfxDeviceWindow::EndRendering(presentContent)) + { + GfxDeviceClient& device = (GfxDeviceClient&)GetGfxDevice(); + device.EndRendering(m_ClientWindow, presentContent); + if (m_Reshaped) + { + GfxDeviceRenderer renderer = device.GetRenderer(); + // We need to complete rendering on WM_PAINT after window was resized + // otherwise contents will look stretched in DirectX mode + if (renderer == kGfxRendererD3D9 || renderer == kGfxRendererD3D11) + device.FinishRendering(); + m_Reshaped = false; + } + return true; + } + else + { + return false; + } +} + +void ThreadedWindow::OnActivateWindow() +{ + GfxDeviceClient& device = (GfxDeviceClient&)GetGfxDevice(); + device.SetActiveRenderTexture(NULL); + device.SetCurrentWindowSize(m_Width, m_Height); + device.SetInvertProjectionMatrix(false); + ms_CurrentFSAALevel = m_FSAALevel; + +} + +#endif diff --git a/Runtime/GfxDevice/threaded/ThreadedWindow.h b/Runtime/GfxDevice/threaded/ThreadedWindow.h new file mode 100644 index 0000000..60489f4 --- /dev/null +++ b/Runtime/GfxDevice/threaded/ThreadedWindow.h @@ -0,0 +1,36 @@ +#ifndef THREADEDWINDOW_H +#define THREADEDWINDOW_H + +#if UNITY_WIN && UNITY_EDITOR + +#include "Runtime/GfxDevice/GfxDeviceWindow.h" +#include "ThreadedDeviceStates.h" + +class ThreadedWindow : public GfxDeviceWindow +{ +public: + ThreadedWindow( HWND window, int width, int height, DepthBufferFormat depthFormat, int antiAlias ); + ~ThreadedWindow(); + + bool Reshape( int width, int height, DepthBufferFormat depthFormat, int antiAlias ); + + bool BeginRendering(); + bool EndRendering( bool presentContent ); + void SetAsActiveWindow(); + + static int GetCurrentFSAALevel() { return ms_CurrentFSAALevel; } + +private: + void OnActivateWindow(); + + friend class GfxDeviceClient; + friend class GfxDeviceWorker; + + ClientDeviceWindow* m_ClientWindow; + int m_FSAALevel; + bool m_Reshaped; + static int ms_CurrentFSAALevel; +}; + +#endif +#endif diff --git a/Runtime/GfxDevice/threaded/WorkerIDMapper.h b/Runtime/GfxDevice/threaded/WorkerIDMapper.h new file mode 100644 index 0000000..9b563f5 --- /dev/null +++ b/Runtime/GfxDevice/threaded/WorkerIDMapper.h @@ -0,0 +1,33 @@ +#ifndef WORKERIDMAPPER_H +#define WORKERIDMAPPER_H + +#include "ClientIDMapper.h" +#include "Runtime/Utilities/dynamic_array.h" + +template <class T> +class WorkerIDMapper { +public: + + WorkerIDMapper () + { + (*this)[0] = NULL; + } + + T*& operator [] (ClientIDMapper::ClientID cid) + { + if (m_IDMapping.size() <= cid) + m_IDMapping.resize_uninitialized(cid+1); + return m_IDMapping[cid]; + } + +private: + dynamic_array<T*> m_IDMapping; +}; + +#if ENABLE_GFXDEVICE_REMOTE_PROCESS +#define WorkerIDWrapper(type,val) m_##type##Mapper[val] +#else +#define WorkerIDWrapper(type,val) val +#endif + +#endif
\ No newline at end of file |