summaryrefslogtreecommitdiff
path: root/Runtime/GfxDevice/threaded
diff options
context:
space:
mode:
Diffstat (limited to 'Runtime/GfxDevice/threaded')
-rw-r--r--Runtime/GfxDevice/threaded/ClientIDMapper.h46
-rw-r--r--Runtime/GfxDevice/threaded/GfxCommands.h669
-rw-r--r--Runtime/GfxDevice/threaded/GfxDeviceClient.cpp3922
-rw-r--r--Runtime/GfxDevice/threaded/GfxDeviceClient.h423
-rw-r--r--Runtime/GfxDevice/threaded/GfxDeviceWorker.cpp2161
-rw-r--r--Runtime/GfxDevice/threaded/GfxDeviceWorker.h135
-rw-r--r--Runtime/GfxDevice/threaded/GfxReturnStructs.cpp239
-rw-r--r--Runtime/GfxDevice/threaded/GfxReturnStructs.h122
-rw-r--r--Runtime/GfxDevice/threaded/ThreadedDeviceStates.h134
-rw-r--r--Runtime/GfxDevice/threaded/ThreadedDisplayList.cpp442
-rw-r--r--Runtime/GfxDevice/threaded/ThreadedDisplayList.h85
-rw-r--r--Runtime/GfxDevice/threaded/ThreadedTimerQuery.cpp102
-rw-r--r--Runtime/GfxDevice/threaded/ThreadedTimerQuery.h29
-rw-r--r--Runtime/GfxDevice/threaded/ThreadedVBO.cpp511
-rw-r--r--Runtime/GfxDevice/threaded/ThreadedVBO.h104
-rw-r--r--Runtime/GfxDevice/threaded/ThreadedWindow.cpp97
-rw-r--r--Runtime/GfxDevice/threaded/ThreadedWindow.h36
-rw-r--r--Runtime/GfxDevice/threaded/WorkerIDMapper.h33
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] = &params;
+#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 = &rect;
+ }
+ 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