source: trunk/Utilities/DirectShowReferenceSource/Sample/Unity01/RenderingPlugin/RenderingPlugin.cpp @ 937

Last change on this file since 937 was 638, checked in by roman, 8 years ago

Media source texture reader and Unity 3D sample project

File size: 34.2 KB
Line 
1// Example low level rendering Unity plugin
2#include "RenderingPlugin.h"
3#include "Unity/IUnityGraphics.h"
4
5#include <cassert>
6#include <cmath>
7#include <cstdio>
8#include <vector>
9#include <string>
10
11// --------------------------------------------------------------------------
12// Include headers for the graphics APIs we support
13
14#if SUPPORT_D3D9
15#       include <d3d9.h>
16#       include "Unity/IUnityGraphicsD3D9.h"
17#endif
18#if SUPPORT_D3D11
19#       include <d3d11.h>
20#       include "Unity/IUnityGraphicsD3D11.h"
21#endif
22#if SUPPORT_D3D12
23#       include <d3d12.h>
24#       include "Unity/IUnityGraphicsD3D12.h"
25#endif
26
27#if SUPPORT_OPENGL_LEGACY
28#       include "GL/glew.h"
29#endif
30#if SUPPORT_OPENGL_UNIFIED
31#       if UNITY_IPHONE
32#               include <OpenGLES/ES2/gl.h>
33#       elif UNITY_ANDROID
34#               include <GLES2/gl2.h>
35#       else
36#               include "GL/glew.h"
37#       endif
38#endif
39
40
41// --------------------------------------------------------------------------
42// Helper utilities
43
44
45// Prints a string
46static void DebugLog (const char* str)
47{
48        #if UNITY_WIN
49        OutputDebugStringA (str);
50        #else
51        printf ("%s", str);
52        #endif
53}
54
55// COM-like Release macro
56#ifndef SAFE_RELEASE
57#define SAFE_RELEASE(a) if (a) { a->Release(); a = NULL; }
58#endif
59
60// --------------------------------------------------------------------------
61
62#include <assert.h>
63
64static float g_Time = 0;
65static void* g_TexturePointer = NULL;
66
67#import "libid:9E3ABA93-C8D8-41D3-B39E-29508FDE5757" raw_interfaces_only // AlaxInfoDirectShowReferenceSource
68
69static AlaxInfoDirectShowReferenceSource::IVideoMediaSourceTextureReader* g_pTextureReader = NULL;
70
71// --------------------------------------------------------------------------
72// SetTimeFromUnity, an example function we export which is called by one of the scripts.
73
74extern "C" void UNITY_INTERFACE_EXPORT UNITY_INTERFACE_API SetTimeFromUnity (float t) 
75{ 
76        if(t < g_Time)
77        {
78                if(g_pTextureReader)
79                {
80                        assert(g_TexturePointer);
81                        g_pTextureReader->Terminate();
82                        g_pTextureReader->Initialize((IUnknown*) g_TexturePointer);
83                }
84        }
85        g_Time = t; 
86}
87
88// --------------------------------------------------------------------------
89// SetTextureFromUnity, an example function we export which is called by one of the scripts.
90
91#ifdef SUPPORT_OPENGL_UNIFIED
92static int   g_TexWidth  = 0;
93static int   g_TexHeight = 0;
94#endif
95
96#if SUPPORT_OPENGL_UNIFIED
97extern "C" void UNITY_INTERFACE_EXPORT UNITY_INTERFACE_API SetTextureFromUnity(void* texturePtr, int w, int h)
98#else
99extern "C" void UNITY_INTERFACE_EXPORT UNITY_INTERFACE_API SetTextureFromUnity(void* texturePtr)
100#endif
101{
102        // A script calls this at initialization time; just remember the texture pointer here.
103        // Will update texture pixels each frame from the plugin rendering event (texture update
104        // needs to happen on the rendering thread).
105        g_TexturePointer = texturePtr;
106#if SUPPORT_OPENGL_UNIFIED
107        g_TexWidth = w;
108        g_TexHeight = h;
109#endif
110}
111
112enum
113{
114        ATTRIB_POSITION = 0,
115        ATTRIB_COLOR = 1
116};
117
118// --------------------------------------------------------------------------
119// SetUnityStreamingAssetsPath, an example function we export which is called by one of the scripts.
120
121static std::string s_UnityStreamingAssetsPath;
122extern "C" void UNITY_INTERFACE_EXPORT UNITY_INTERFACE_API SetUnityStreamingAssetsPath(const char* path)
123{
124        s_UnityStreamingAssetsPath = path;
125}
126
127
128
129// --------------------------------------------------------------------------
130// UnitySetInterfaces
131
132static void UNITY_INTERFACE_API OnGraphicsDeviceEvent(UnityGfxDeviceEventType eventType);
133
134static IUnityInterfaces* s_UnityInterfaces = NULL;
135static IUnityGraphics* s_Graphics = NULL;
136static UnityGfxRenderer s_DeviceType = kUnityGfxRendererNull;
137
138extern "C" void UNITY_INTERFACE_EXPORT UNITY_INTERFACE_API UnityPluginLoad(IUnityInterfaces* unityInterfaces)
139{
140        s_UnityInterfaces = unityInterfaces;
141        s_Graphics = s_UnityInterfaces->Get<IUnityGraphics>();
142        s_Graphics->RegisterDeviceEventCallback(OnGraphicsDeviceEvent);
143       
144        // Run OnGraphicsDeviceEvent(initialize) manually on plugin load
145        OnGraphicsDeviceEvent(kUnityGfxDeviceEventInitialize);
146}
147
148extern "C" void UNITY_INTERFACE_EXPORT UNITY_INTERFACE_API UnityPluginUnload()
149{
150        s_Graphics->UnregisterDeviceEventCallback(OnGraphicsDeviceEvent);
151}
152
153
154
155// --------------------------------------------------------------------------
156// GraphicsDeviceEvent
157
158// Actual setup/teardown functions defined below
159#if SUPPORT_D3D9
160static void DoEventGraphicsDeviceD3D9(UnityGfxDeviceEventType eventType);
161#endif
162#if SUPPORT_D3D11
163static void DoEventGraphicsDeviceD3D11(UnityGfxDeviceEventType eventType);
164#endif
165#if SUPPORT_D3D12
166static void DoEventGraphicsDeviceD3D12(UnityGfxDeviceEventType eventType);
167#endif
168#if SUPPORT_OPENGL_UNIFIED
169static void DoEventGraphicsDeviceGLUnified(UnityGfxDeviceEventType eventType);
170#endif
171
172static void UNITY_INTERFACE_API OnGraphicsDeviceEvent(UnityGfxDeviceEventType eventType)
173{
174        UnityGfxRenderer currentDeviceType = s_DeviceType;
175
176        switch (eventType)
177        {
178        case kUnityGfxDeviceEventInitialize:
179                {
180                        DebugLog("OnGraphicsDeviceEvent(Initialize).\n");
181                        s_DeviceType = s_Graphics->GetRenderer();
182                        currentDeviceType = s_DeviceType;
183                        break;
184                }
185
186        case kUnityGfxDeviceEventShutdown:
187                {
188                        DebugLog("OnGraphicsDeviceEvent(Shutdown).\n");
189                        s_DeviceType = kUnityGfxRendererNull;
190                        g_TexturePointer = NULL;
191                        break;
192                }
193
194        case kUnityGfxDeviceEventBeforeReset:
195                {
196                        DebugLog("OnGraphicsDeviceEvent(BeforeReset).\n");
197                        break;
198                }
199
200        case kUnityGfxDeviceEventAfterReset:
201                {
202                        DebugLog("OnGraphicsDeviceEvent(AfterReset).\n");
203                        break;
204                }
205        };
206
207        #if SUPPORT_D3D9
208        if (currentDeviceType == kUnityGfxRendererD3D9)
209                DoEventGraphicsDeviceD3D9(eventType);
210        #endif
211
212        #if SUPPORT_D3D11
213        if (currentDeviceType == kUnityGfxRendererD3D11)
214                DoEventGraphicsDeviceD3D11(eventType);
215        #endif
216
217        #if SUPPORT_D3D12
218        if (currentDeviceType == kUnityGfxRendererD3D12)
219                DoEventGraphicsDeviceD3D12(eventType);
220        #endif
221       
222        #if SUPPORT_OPENGL_UNIFIED
223        if (currentDeviceType == kUnityGfxRendererOpenGLES20 ||
224                currentDeviceType == kUnityGfxRendererOpenGLES30 ||
225                currentDeviceType == kUnityGfxRendererOpenGLCore)
226                DoEventGraphicsDeviceGLUnified(eventType);
227        #endif
228}
229
230
231
232// --------------------------------------------------------------------------
233// OnRenderEvent
234// This will be called for GL.IssuePluginEvent script calls; eventID will
235// be the integer passed to IssuePluginEvent. In this example, we just ignore
236// that value.
237
238
239struct MyVertex {
240        float x, y, z;
241        unsigned int color;
242};
243static void SetDefaultGraphicsState ();
244static void DoRendering (const float* worldMatrix, const float* identityMatrix, float* projectionMatrix, const MyVertex* verts);
245
246static void UNITY_INTERFACE_API OnRenderEvent(int eventID)
247{
248        // Unknown graphics device type? Do nothing.
249        if (s_DeviceType == kUnityGfxRendererNull)
250                return;
251
252
253        // A colored triangle. Note that colors will come out differently
254        // in D3D9/11 and OpenGL, for example, since they expect color bytes
255        // in different ordering.
256        MyVertex verts[3] = {
257                { -0.5f, -0.25f,  0, 0xFFff0000 },
258                {  0.5f, -0.25f,  0, 0xFF00ff00 },
259                {  0,     0.5f ,  0, 0xFF0000ff },
260        };
261
262
263        // Some transformation matrices: rotate around Z axis for world
264        // matrix, identity view matrix, and identity projection matrix.
265
266        float phi = g_Time;
267        float cosPhi = cosf(phi);
268        float sinPhi = sinf(phi);
269
270        float worldMatrix[16] = {
271                cosPhi,-sinPhi,0,0,
272                sinPhi,cosPhi,0,0,
273                0,0,1,0,
274                0,0,0.7f,1,
275        };
276        float identityMatrix[16] = {
277                1,0,0,0,
278                0,1,0,0,
279                0,0,1,0,
280                0,0,0,1,
281        };
282        float projectionMatrix[16] = {
283                1,0,0,0,
284                0,1,0,0,
285                0,0,1,0,
286                0,0,0,1,
287        };
288
289        // Actual functions defined below
290        SetDefaultGraphicsState ();
291        DoRendering (worldMatrix, identityMatrix, projectionMatrix, verts);
292}
293
294// --------------------------------------------------------------------------
295// GetRenderEventFunc, an example function we export which is used to get a rendering event callback function.
296extern "C" UnityRenderingEvent UNITY_INTERFACE_EXPORT UNITY_INTERFACE_API GetRenderEventFunc()
297{
298        return OnRenderEvent;
299}
300
301
302
303// -------------------------------------------------------------------
304// Shared code
305
306#if SUPPORT_D3D11
307typedef std::vector<unsigned char> Buffer;
308bool LoadFileIntoBuffer(const std::string& fileName, Buffer& data)
309{
310        FILE* fp;
311        fopen_s(&fp, fileName.c_str(), "rb");
312        if (fp)
313        {
314                fseek (fp, 0, SEEK_END);
315                int size = ftell (fp);
316                fseek (fp, 0, SEEK_SET);
317                data.resize(size);
318
319                fread(&data[0], size, 1, fp);
320
321                fclose(fp);
322
323                return true;
324        }
325        else
326        {
327                std::string errorMessage = "Failed to find ";
328                errorMessage += fileName;
329                DebugLog(errorMessage.c_str());
330                return false;
331        }
332}
333#endif
334
335
336// -------------------------------------------------------------------
337//  Direct3D 9 setup/teardown code
338
339
340#if SUPPORT_D3D9
341
342static IDirect3DDevice9* g_D3D9Device;
343
344// A dynamic vertex buffer just to demonstrate how to handle D3D9 device resets.
345static IDirect3DVertexBuffer9* g_D3D9DynamicVB;
346
347static void DoEventGraphicsDeviceD3D9(UnityGfxDeviceEventType eventType)
348{
349        // Create or release a small dynamic vertex buffer depending on the event type.
350        switch (eventType) {
351        case kUnityGfxDeviceEventInitialize:
352                {
353                        IUnityGraphicsD3D9* d3d9 = s_UnityInterfaces->Get<IUnityGraphicsD3D9>();
354                        g_D3D9Device = d3d9->GetDevice();
355                }
356        case kUnityGfxDeviceEventAfterReset:
357                // After device is initialized or was just reset, create the VB.
358                if (!g_D3D9DynamicVB)
359                        g_D3D9Device->CreateVertexBuffer (1024, D3DUSAGE_WRITEONLY | D3DUSAGE_DYNAMIC, 0, D3DPOOL_DEFAULT, &g_D3D9DynamicVB, NULL);
360                break;
361        case kUnityGfxDeviceEventBeforeReset:
362        case kUnityGfxDeviceEventShutdown:
363                // Before device is reset or being shut down, release the VB.
364                SAFE_RELEASE(g_D3D9DynamicVB);
365                break;
366        }
367}
368
369#endif // #if SUPPORT_D3D9
370
371
372
373// -------------------------------------------------------------------
374//  Direct3D 11 setup/teardown code
375
376
377#if SUPPORT_D3D11
378
379static ID3D11Device* g_D3D11Device = NULL;
380static ID3D11Buffer* g_D3D11VB = NULL; // vertex buffer
381static ID3D11Buffer* g_D3D11CB = NULL; // constant buffer
382static ID3D11VertexShader* g_D3D11VertexShader = NULL;
383static ID3D11PixelShader* g_D3D11PixelShader = NULL;
384static ID3D11InputLayout* g_D3D11InputLayout = NULL;
385static ID3D11RasterizerState* g_D3D11RasterState = NULL;
386static ID3D11BlendState* g_D3D11BlendState = NULL;
387static ID3D11DepthStencilState* g_D3D11DepthState = NULL;
388
389static D3D11_INPUT_ELEMENT_DESC s_DX11InputElementDesc[] = {
390        { "POSITION", 0, DXGI_FORMAT_R32G32B32_FLOAT, 0, 0, D3D11_INPUT_PER_VERTEX_DATA, 0 },
391        { "COLOR", 0, DXGI_FORMAT_R8G8B8A8_UNORM, 0, 12, D3D11_INPUT_PER_VERTEX_DATA, 0 },
392};
393
394static bool EnsureD3D11ResourcesAreCreated()
395{
396        if (g_D3D11VertexShader)
397                return true;
398
399        // D3D11 has to load resources. Wait for Unity to provide the streaming assets path first.
400        if (s_UnityStreamingAssetsPath.empty())
401                return false;
402
403        D3D11_BUFFER_DESC desc;
404        memset (&desc, 0, sizeof(desc));
405
406        // vertex buffer
407        desc.Usage = D3D11_USAGE_DEFAULT;
408        desc.ByteWidth = 1024;
409        desc.BindFlags = D3D11_BIND_VERTEX_BUFFER;
410        g_D3D11Device->CreateBuffer (&desc, NULL, &g_D3D11VB);
411
412        // constant buffer
413        desc.Usage = D3D11_USAGE_DEFAULT;
414        desc.ByteWidth = 64; // hold 1 matrix
415        desc.BindFlags = D3D11_BIND_CONSTANT_BUFFER;
416        desc.CPUAccessFlags = 0;
417        g_D3D11Device->CreateBuffer (&desc, NULL, &g_D3D11CB);
418
419
420        HRESULT hr = -1;
421        Buffer vertexShader;
422        Buffer pixelShader;
423        std::string vertexShaderPath(s_UnityStreamingAssetsPath);
424        vertexShaderPath += "/Shaders/DX11_9_1/SimpleVertexShader.cso";
425        std::string fragmentShaderPath(s_UnityStreamingAssetsPath);
426        fragmentShaderPath += "/Shaders/DX11_9_1/SimplePixelShader.cso";
427        LoadFileIntoBuffer(vertexShaderPath, vertexShader);
428        LoadFileIntoBuffer(fragmentShaderPath, pixelShader);
429
430        if (vertexShader.size() > 0 && pixelShader.size() > 0)
431        {
432                hr = g_D3D11Device->CreateVertexShader(&vertexShader[0], vertexShader.size(), nullptr, &g_D3D11VertexShader);
433                if (FAILED(hr)) DebugLog("Failed to create vertex shader.\n");
434                hr = g_D3D11Device->CreatePixelShader(&pixelShader[0], pixelShader.size(), nullptr, &g_D3D11PixelShader);
435                if (FAILED(hr)) DebugLog("Failed to create pixel shader.\n");
436        }
437        else
438        {
439                DebugLog("Failed to load vertex or pixel shader.\n");
440        }
441        // input layout
442        if (g_D3D11VertexShader && vertexShader.size() > 0)
443        {
444                g_D3D11Device->CreateInputLayout (s_DX11InputElementDesc, 2, &vertexShader[0], vertexShader.size(), &g_D3D11InputLayout);
445        }
446
447        // render states
448        D3D11_RASTERIZER_DESC rsdesc;
449        memset (&rsdesc, 0, sizeof(rsdesc));
450        rsdesc.FillMode = D3D11_FILL_SOLID;
451        rsdesc.CullMode = D3D11_CULL_NONE;
452        rsdesc.DepthClipEnable = TRUE;
453        g_D3D11Device->CreateRasterizerState (&rsdesc, &g_D3D11RasterState);
454
455        D3D11_DEPTH_STENCIL_DESC dsdesc;
456        memset (&dsdesc, 0, sizeof(dsdesc));
457        dsdesc.DepthEnable = TRUE;
458        dsdesc.DepthWriteMask = D3D11_DEPTH_WRITE_MASK_ZERO;
459        dsdesc.DepthFunc = D3D11_COMPARISON_LESS_EQUAL;
460        g_D3D11Device->CreateDepthStencilState (&dsdesc, &g_D3D11DepthState);
461
462        D3D11_BLEND_DESC bdesc;
463        memset (&bdesc, 0, sizeof(bdesc));
464        bdesc.RenderTarget[0].BlendEnable = FALSE;
465        bdesc.RenderTarget[0].RenderTargetWriteMask = 0xF;
466        g_D3D11Device->CreateBlendState (&bdesc, &g_D3D11BlendState);
467
468        #pragma region Reference Source Texture Reader
469        {
470                using namespace AlaxInfoDirectShowReferenceSource;
471                if(g_pTextureReader)
472                {
473                        g_pTextureReader->Release();
474                        g_pTextureReader = NULL;
475                }
476                CoCreateInstance(__uuidof(VideoMediaSourceTextureReader), NULL, CLSCTX_ALL, __uuidof(IVideoMediaSourceTextureReader), (VOID**) &g_pTextureReader);
477                g_pTextureReader->Initialize((IUnknown*) g_TexturePointer);
478        }
479        #pragma endregion
480
481        return true;
482}
483
484static void ReleaseD3D11Resources()
485{
486        SAFE_RELEASE(g_D3D11VB);
487        SAFE_RELEASE(g_D3D11CB);
488        SAFE_RELEASE(g_D3D11VertexShader);
489        SAFE_RELEASE(g_D3D11PixelShader);
490        SAFE_RELEASE(g_D3D11InputLayout);
491        SAFE_RELEASE(g_D3D11RasterState);
492        SAFE_RELEASE(g_D3D11BlendState);
493        SAFE_RELEASE(g_D3D11DepthState);
494        if(g_pTextureReader)
495        {
496                g_pTextureReader->Terminate();
497                g_pTextureReader->Release();
498                g_pTextureReader = NULL;
499        }
500}
501
502static void DoEventGraphicsDeviceD3D11(UnityGfxDeviceEventType eventType)
503{
504        if (eventType == kUnityGfxDeviceEventInitialize)
505        {
506                IUnityGraphicsD3D11* d3d11 = s_UnityInterfaces->Get<IUnityGraphicsD3D11>();
507                g_D3D11Device = d3d11->GetDevice();
508               
509                EnsureD3D11ResourcesAreCreated();
510        }
511        else if (eventType == kUnityGfxDeviceEventShutdown)
512        {
513                ReleaseD3D11Resources();
514        }
515}
516
517#endif // #if SUPPORT_D3D11
518
519
520
521// -------------------------------------------------------------------
522// Direct3D 12 setup/teardown code
523
524
525#if SUPPORT_D3D12
526const UINT kNodeMask = 0;
527
528static IUnityGraphicsD3D12* s_D3D12 = NULL;
529static ID3D12Resource* s_D3D12Upload = NULL;
530
531static ID3D12CommandAllocator* s_D3D12CmdAlloc = NULL;
532static ID3D12GraphicsCommandList* s_D3D12CmdList = NULL;
533
534static ID3D12Fence* s_D3D12Fence = NULL;
535static UINT64 s_D3D12FenceValue = 1;
536static HANDLE s_D3D12Event = NULL;
537
538ID3D12Resource* GetD3D12UploadResource(UINT64 size)
539{
540        if (s_D3D12Upload)
541        {
542                D3D12_RESOURCE_DESC desc = s_D3D12Upload->GetDesc();
543                if (desc.Width == size)
544                        return s_D3D12Upload;
545                else
546                        s_D3D12Upload->Release();
547        }
548
549        // Texture upload buffer
550        D3D12_HEAP_PROPERTIES heapProps = {};
551        heapProps.Type = D3D12_HEAP_TYPE_UPLOAD;
552        heapProps.CPUPageProperty = D3D12_CPU_PAGE_PROPERTY_UNKNOWN;
553        heapProps.MemoryPoolPreference = D3D12_MEMORY_POOL_UNKNOWN;
554        heapProps.CreationNodeMask = kNodeMask;
555        heapProps.VisibleNodeMask = kNodeMask;
556
557        D3D12_RESOURCE_DESC heapDesc = {};
558        heapDesc.Dimension = D3D12_RESOURCE_DIMENSION_BUFFER;
559        heapDesc.Alignment = 0;
560        heapDesc.Width = size;
561        heapDesc.Height = 1;
562        heapDesc.DepthOrArraySize = 1;
563        heapDesc.MipLevels = 1;
564        heapDesc.Format = DXGI_FORMAT_UNKNOWN;
565        heapDesc.SampleDesc.Count = 1;
566        heapDesc.SampleDesc.Quality = 0;
567        heapDesc.Layout = D3D12_TEXTURE_LAYOUT_ROW_MAJOR;
568        heapDesc.Flags = D3D12_RESOURCE_FLAG_NONE;
569
570        ID3D12Device* device = s_D3D12->GetDevice();
571        HRESULT hr = device->CreateCommittedResource(
572                        &heapProps,
573                        D3D12_HEAP_FLAG_NONE,
574                        &heapDesc,
575                        D3D12_RESOURCE_STATE_GENERIC_READ,
576                        nullptr,
577                        IID_PPV_ARGS(&s_D3D12Upload));
578        if (FAILED(hr)) DebugLog("Failed to CreateCommittedResource.\n");
579
580        return s_D3D12Upload;
581}
582
583static void CreateD3D12Resources()
584{
585        ID3D12Device* device = s_D3D12->GetDevice();
586
587        HRESULT hr = E_FAIL;
588
589        // Command list
590        hr = device->CreateCommandAllocator(D3D12_COMMAND_LIST_TYPE_DIRECT, IID_PPV_ARGS(&s_D3D12CmdAlloc));
591        if (FAILED(hr)) DebugLog("Failed to CreateCommandAllocator.\n");
592        hr = device->CreateCommandList(kNodeMask, D3D12_COMMAND_LIST_TYPE_DIRECT, s_D3D12CmdAlloc, nullptr, IID_PPV_ARGS(&s_D3D12CmdList));
593        if (FAILED(hr)) DebugLog("Failed to CreateCommandList.\n");
594        s_D3D12CmdList->Close();
595
596        // Fence
597        s_D3D12FenceValue = 1;
598        device->CreateFence(s_D3D12FenceValue, D3D12_FENCE_FLAG_NONE, IID_PPV_ARGS(&s_D3D12Fence));
599        if (FAILED(hr)) DebugLog("Failed to CreateFence.\n");
600        s_D3D12Event = CreateEvent(nullptr, FALSE, FALSE, nullptr);
601}
602
603static void ReleaseD3D12Resources()
604{
605        SAFE_RELEASE(s_D3D12Upload);
606       
607        if (s_D3D12Event)
608                CloseHandle(s_D3D12Event);
609
610        SAFE_RELEASE(s_D3D12Fence);
611        SAFE_RELEASE(s_D3D12CmdList);
612        SAFE_RELEASE(s_D3D12CmdAlloc);
613}
614
615static void DoEventGraphicsDeviceD3D12(UnityGfxDeviceEventType eventType)
616{
617        if (eventType == kUnityGfxDeviceEventInitialize)
618        {
619                s_D3D12 = s_UnityInterfaces->Get<IUnityGraphicsD3D12>();
620                CreateD3D12Resources();
621        }
622        else if (eventType == kUnityGfxDeviceEventShutdown)
623        {
624                ReleaseD3D12Resources();
625        }
626}
627#endif // #if SUPPORT_D3D12
628
629
630
631// -------------------------------------------------------------------
632// OpenGL ES / Core setup/teardown code
633
634
635#if SUPPORT_OPENGL_UNIFIED
636
637#define VPROG_SRC(ver, attr, varying)                                                           \
638        ver                                                                                                                             \
639        attr " highp vec3 pos;\n"                                                                               \
640        attr " lowp vec4 color;\n"                                                                              \
641        "\n"                                                                                                                    \
642        varying " lowp vec4 ocolor;\n"                                                                  \
643        "\n"                                                                                                                    \
644        "uniform highp mat4 worldMatrix;\n"                                                             \
645        "uniform highp mat4 projMatrix;\n"                                                              \
646        "\n"                                                                                                                    \
647        "void main()\n"                                                                                                 \
648        "{\n"                                                                                                                   \
649        "       gl_Position = (projMatrix * worldMatrix) * vec4(pos,1);\n"      \
650        "       ocolor = color;\n"                                                                                      \
651        "}\n"                                                                                                                   \
652
653static const char* kGlesVProgTextGLES2          = VPROG_SRC("\n", "attribute", "varying");
654static const char* kGlesVProgTextGLES3          = VPROG_SRC("#version 300 es\n", "in", "out");
655static const char* kGlesVProgTextGLCore         = VPROG_SRC("#version 150\n", "in", "out");
656
657#undef VPROG_SRC
658
659#define FSHADER_SRC(ver, varying, outDecl, outVar)      \
660        ver                                                                                             \
661        outDecl                                                                                 \
662        varying " lowp vec4 ocolor;\n"                                  \
663        "\n"                                                                                    \
664        "void main()\n"                                                                 \
665        "{\n"                                                                                   \
666        "       " outVar " = ocolor;\n"                                         \
667        "}\n"                                                                                   \
668
669static const char* kGlesFShaderTextGLES2        = FSHADER_SRC("\n", "varying", "\n", "gl_FragColor");
670static const char* kGlesFShaderTextGLES3        = FSHADER_SRC("#version 300 es\n", "in", "out lowp vec4 fragColor;\n", "fragColor");
671static const char* kGlesFShaderTextGLCore       = FSHADER_SRC("#version 150\n", "in", "out lowp vec4 fragColor;\n", "fragColor");
672
673#undef FSHADER_SRC
674
675static GLuint   g_VProg;
676static GLuint   g_FShader;
677static GLuint   g_Program;
678static GLuint   g_VertexArray;
679static GLuint   g_ArrayBuffer;
680static int              g_WorldMatrixUniformIndex;
681static int              g_ProjMatrixUniformIndex;
682
683static GLuint CreateShader(GLenum type, const char* text)
684{
685        GLuint ret = glCreateShader(type);
686        glShaderSource(ret, 1, &text, NULL);
687        glCompileShader(ret);
688
689        return ret;
690}
691
692static void DoEventGraphicsDeviceGLUnified(UnityGfxDeviceEventType eventType)
693{
694        if (eventType == kUnityGfxDeviceEventInitialize)
695        {
696                if (s_DeviceType == kUnityGfxRendererOpenGLES20)
697                {
698                        ::printf("OpenGLES 2.0 device\n");
699                        g_VProg         = CreateShader(GL_VERTEX_SHADER, kGlesVProgTextGLES2);
700                        g_FShader       = CreateShader(GL_FRAGMENT_SHADER, kGlesFShaderTextGLES2);
701                }
702                else if(s_DeviceType == kUnityGfxRendererOpenGLES30)
703                {
704                        ::printf("OpenGLES 3.0 device\n");
705                        g_VProg         = CreateShader(GL_VERTEX_SHADER, kGlesVProgTextGLES3);
706                        g_FShader       = CreateShader(GL_FRAGMENT_SHADER, kGlesFShaderTextGLES3);
707                }
708#if SUPPORT_OPENGL_CORE
709                else if(s_DeviceType == kUnityGfxRendererOpenGLCore)
710                {
711                        ::printf("OpenGL Core device\n");
712                        glewExperimental = GL_TRUE;
713                        glewInit();
714                        glGetError(); // Clean up error generated by glewInit
715
716                        g_VProg         = CreateShader(GL_VERTEX_SHADER, kGlesVProgTextGLCore);
717                        g_FShader       = CreateShader(GL_FRAGMENT_SHADER, kGlesFShaderTextGLCore);
718                }
719#endif
720
721                glGenBuffers(1, &g_ArrayBuffer);
722                glBindBuffer(GL_ARRAY_BUFFER, g_ArrayBuffer);
723                glBufferData(GL_ARRAY_BUFFER, sizeof(MyVertex) * 3, NULL, GL_STREAM_DRAW);
724
725                g_Program = glCreateProgram();
726                glBindAttribLocation(g_Program, ATTRIB_POSITION, "pos");
727                glBindAttribLocation(g_Program, ATTRIB_COLOR, "color");
728                glAttachShader(g_Program, g_VProg);
729                glAttachShader(g_Program, g_FShader);
730#if SUPPORT_OPENGL_CORE
731                if(s_DeviceType == kUnityGfxRendererOpenGLCore)
732                        glBindFragDataLocation(g_Program, 0, "fragColor");
733#endif
734                glLinkProgram(g_Program);
735
736                GLint status = 0;
737                glGetProgramiv(g_Program, GL_LINK_STATUS, &status);
738                assert(status == GL_TRUE);
739
740                g_WorldMatrixUniformIndex       = glGetUniformLocation(g_Program, "worldMatrix");
741                g_ProjMatrixUniformIndex        = glGetUniformLocation(g_Program, "projMatrix");
742
743                assert(glGetError() == GL_NO_ERROR);
744        }
745        else if (eventType == kUnityGfxDeviceEventShutdown)
746        {
747               
748        }
749}
750#endif
751
752
753
754// --------------------------------------------------------------------------
755// SetDefaultGraphicsState
756//
757// Helper function to setup some "sane" graphics state. Rendering state
758// upon call into our plugin can be almost completely arbitrary depending
759// on what was rendered in Unity before.
760// Before calling into the plugin, Unity will set shaders to null,
761// and will unbind most of "current" objects (e.g. VBOs in OpenGL case).
762//
763// Here, we set culling off, lighting off, alpha blend & test off, Z
764// comparison to less equal, and Z writes off.
765
766static void SetDefaultGraphicsState ()
767{
768        #if SUPPORT_D3D9
769        // D3D9 case
770        if (s_DeviceType == kUnityGfxRendererD3D9)
771        {
772                g_D3D9Device->SetRenderState (D3DRS_CULLMODE, D3DCULL_NONE);
773                g_D3D9Device->SetRenderState (D3DRS_LIGHTING, FALSE);
774                g_D3D9Device->SetRenderState (D3DRS_ALPHABLENDENABLE, FALSE);
775                g_D3D9Device->SetRenderState (D3DRS_ALPHATESTENABLE, FALSE);
776                g_D3D9Device->SetRenderState (D3DRS_ZFUNC, D3DCMP_LESSEQUAL);
777                g_D3D9Device->SetRenderState (D3DRS_ZWRITEENABLE, FALSE);
778        }
779        #endif
780
781
782        #if SUPPORT_D3D11
783        // D3D11 case
784        if (s_DeviceType == kUnityGfxRendererD3D11)
785        {
786                ID3D11DeviceContext* ctx = NULL;
787                g_D3D11Device->GetImmediateContext (&ctx);
788                ctx->OMSetDepthStencilState (g_D3D11DepthState, 0);
789                ctx->RSSetState (g_D3D11RasterState);
790                ctx->OMSetBlendState (g_D3D11BlendState, NULL, 0xFFFFFFFF);
791                ctx->Release();
792        }
793        #endif
794
795
796        #if SUPPORT_D3D12
797        // D3D12 case
798        if (s_DeviceType == kUnityGfxRendererD3D12)
799        {
800                // Stateless. Nothing to do.
801        }
802        #endif
803
804
805        #if SUPPORT_OPENGL_LEGACY
806        // OpenGL 2 legacy case (deprecated)
807        if (s_DeviceType == kUnityGfxRendererOpenGL)
808        {
809                glDisable (GL_CULL_FACE);
810                glDisable (GL_LIGHTING);
811                glDisable (GL_BLEND);
812                glDisable (GL_ALPHA_TEST);
813                glDepthFunc (GL_LEQUAL);
814                glEnable (GL_DEPTH_TEST);
815                glDepthMask (GL_FALSE);
816        }
817        #endif
818       
819       
820        #if SUPPORT_OPENGL_UNIFIED
821        // OpenGL ES / core case
822        if (s_DeviceType == kUnityGfxRendererOpenGLES20 ||
823                s_DeviceType == kUnityGfxRendererOpenGLES30 ||
824                s_DeviceType == kUnityGfxRendererOpenGLCore)
825        {
826                glDisable(GL_CULL_FACE);
827                glDisable(GL_BLEND);
828                glDepthFunc(GL_LEQUAL);
829                glEnable(GL_DEPTH_TEST);
830                glDepthMask(GL_FALSE);
831
832                assert(glGetError() == GL_NO_ERROR);
833        }
834        #endif
835}
836
837
838static void FillTextureFromCode (int width, int height, int stride, unsigned char* dst)
839{
840        const float t = g_Time * 4.0f;
841
842        for (int y = 0; y < height; ++y)
843        {
844                unsigned char* ptr = dst;
845                for (int x = 0; x < width; ++x)
846                {
847                        // Simple oldskool "plasma effect", a bunch of combined sine waves
848                        int vv = int(
849                                (127.0f + (127.0f * sinf(x/7.0f+t))) +
850                                (127.0f + (127.0f * sinf(y/5.0f-t))) +
851                                (127.0f + (127.0f * sinf((x+y)/6.0f-t))) +
852                                (127.0f + (127.0f * sinf(sqrtf(float(x*x + y*y))/4.0f-t)))
853                                ) / 4;
854
855                        // Write the texture pixel
856                        ptr[0] = vv;
857                        ptr[1] = vv;
858                        ptr[2] = vv;
859                        ptr[3] = vv;
860
861                        // To next pixel (our pixels are 4 bpp)
862                        ptr += 4;
863                }
864
865                // To next image row
866                dst += stride;
867        }
868}
869
870
871static void DoRendering (const float* worldMatrix, const float* identityMatrix, float* projectionMatrix, const MyVertex* verts)
872{
873        // Does actual rendering of a simple triangle
874
875        #if SUPPORT_D3D9
876        // D3D9 case
877        if (s_DeviceType == kUnityGfxRendererD3D9)
878        {
879                // Transformation matrices
880                g_D3D9Device->SetTransform (D3DTS_WORLD, (const D3DMATRIX*)worldMatrix);
881                g_D3D9Device->SetTransform (D3DTS_VIEW, (const D3DMATRIX*)identityMatrix);
882                g_D3D9Device->SetTransform (D3DTS_PROJECTION, (const D3DMATRIX*)projectionMatrix);
883
884                // Vertex layout
885                g_D3D9Device->SetFVF (D3DFVF_XYZ|D3DFVF_DIFFUSE);
886
887                // Texture stage states to output vertex color
888                g_D3D9Device->SetTextureStageState (0, D3DTSS_COLOROP, D3DTOP_SELECTARG1);
889                g_D3D9Device->SetTextureStageState (0, D3DTSS_COLORARG1, D3DTA_CURRENT);
890                g_D3D9Device->SetTextureStageState (0, D3DTSS_ALPHAOP, D3DTOP_SELECTARG1);
891                g_D3D9Device->SetTextureStageState (0, D3DTSS_ALPHAARG1, D3DTA_CURRENT);
892                g_D3D9Device->SetTextureStageState (1, D3DTSS_COLOROP, D3DTOP_DISABLE);
893                g_D3D9Device->SetTextureStageState (1, D3DTSS_ALPHAOP, D3DTOP_DISABLE);
894
895                // Copy vertex data into our small dynamic vertex buffer. We could have used
896                // DrawPrimitiveUP just fine as well.
897                void* vbPtr;
898                g_D3D9DynamicVB->Lock (0, 0, &vbPtr, D3DLOCK_DISCARD);
899                memcpy (vbPtr, verts, sizeof(verts[0])*3);
900                g_D3D9DynamicVB->Unlock ();
901                g_D3D9Device->SetStreamSource (0, g_D3D9DynamicVB, 0, sizeof(MyVertex));
902
903                // Draw!
904                g_D3D9Device->DrawPrimitive (D3DPT_TRIANGLELIST, 0, 1);
905
906                // Update native texture from code
907                if (g_TexturePointer)
908                {
909                        IDirect3DTexture9* d3dtex = (IDirect3DTexture9*)g_TexturePointer;
910                        D3DSURFACE_DESC desc;
911                        d3dtex->GetLevelDesc (0, &desc);
912                        D3DLOCKED_RECT lr;
913                        d3dtex->LockRect (0, &lr, NULL, 0);
914                        FillTextureFromCode (desc.Width, desc.Height, lr.Pitch, (unsigned char*)lr.pBits);
915                        d3dtex->UnlockRect (0);
916                }
917        }
918        #endif
919
920
921        #if SUPPORT_D3D11
922        // D3D11 case
923        if (s_DeviceType == kUnityGfxRendererD3D11 && EnsureD3D11ResourcesAreCreated())
924        {
925                ID3D11DeviceContext* ctx = NULL;
926                g_D3D11Device->GetImmediateContext (&ctx);
927/*
928                // update constant buffer - just the world matrix in our case
929                ctx->UpdateSubresource (g_D3D11CB, 0, NULL, worldMatrix, 64, 0);
930
931                // set shaders
932                ctx->VSSetConstantBuffers (0, 1, &g_D3D11CB);
933                ctx->VSSetShader (g_D3D11VertexShader, NULL, 0);
934                ctx->PSSetShader (g_D3D11PixelShader, NULL, 0);
935
936                // update vertex buffer
937                ctx->UpdateSubresource (g_D3D11VB, 0, NULL, verts, sizeof(verts[0])*3, 0);
938
939                // set input assembler data and draw
940                ctx->IASetInputLayout (g_D3D11InputLayout);
941                ctx->IASetPrimitiveTopology (D3D11_PRIMITIVE_TOPOLOGY_TRIANGLELIST);
942                UINT stride = sizeof(MyVertex);
943                UINT offset = 0;
944                ctx->IASetVertexBuffers (0, 1, &g_D3D11VB, &stride, &offset);
945                ctx->Draw (3, 0);
946*/
947                // update native texture from code
948                if (g_TexturePointer)
949                {
950/*
951                        ID3D11Texture2D* d3dtex = (ID3D11Texture2D*)g_TexturePointer;
952                        D3D11_TEXTURE2D_DESC desc;
953                        d3dtex->GetDesc (&desc);
954
955                        unsigned char* data = new unsigned char[desc.Width*desc.Height*4];
956                        FillTextureFromCode (desc.Width, desc.Height, desc.Width*4, data);
957                        ctx->UpdateSubresource (d3dtex, 0, NULL, data, desc.Width*4, 0);
958                        delete[] data;
959*/
960                        g_pTextureReader->Update((DOUBLE) g_Time);
961                }
962
963                ctx->Release();
964        }
965        #endif
966
967
968
969        #if SUPPORT_D3D12
970        // D3D12 case
971        if (s_DeviceType == kUnityGfxRendererD3D12)
972        {
973                ID3D12Device* device = s_D3D12->GetDevice();
974                ID3D12CommandQueue* queue = s_D3D12->GetCommandQueue();
975
976                // Wait on the previous job (example only - simplifies resource management)
977                if (s_D3D12Fence->GetCompletedValue() < s_D3D12FenceValue)
978                {
979                        s_D3D12Fence->SetEventOnCompletion(s_D3D12FenceValue, s_D3D12Event);
980                        WaitForSingleObject(s_D3D12Event, INFINITE);
981                }
982               
983                // Update native texture from code
984                if (g_TexturePointer)
985                {
986                        ID3D12Resource* resource = (ID3D12Resource*)g_TexturePointer;
987                        D3D12_RESOURCE_DESC desc = resource->GetDesc();
988
989                        // Begin a command list
990                        s_D3D12CmdAlloc->Reset();
991                        s_D3D12CmdList->Reset(s_D3D12CmdAlloc, nullptr);
992
993                        // Fill data
994                        const UINT64 kDataSize = desc.Width*desc.Height*4;
995                        ID3D12Resource* upload = GetD3D12UploadResource(kDataSize);
996                        void* mapped = NULL;
997                        upload->Map(0, NULL, &mapped);
998                        FillTextureFromCode(desc.Width, desc.Height, desc.Width*4, (unsigned char*)mapped);
999                        upload->Unmap(0, NULL);
1000
1001                        D3D12_TEXTURE_COPY_LOCATION srcLoc = {};
1002                        srcLoc.pResource = upload;
1003                        srcLoc.Type = D3D12_TEXTURE_COPY_TYPE_PLACED_FOOTPRINT;
1004                        device->GetCopyableFootprints(&desc, 0, 1, 0, &srcLoc.PlacedFootprint, nullptr, nullptr, nullptr);
1005
1006                        D3D12_TEXTURE_COPY_LOCATION dstLoc = {};
1007                        dstLoc.pResource = resource;
1008                        dstLoc.Type = D3D12_TEXTURE_COPY_TYPE_SUBRESOURCE_INDEX;
1009                        dstLoc.SubresourceIndex = 0;
1010
1011                        // Queue data upload
1012                        const D3D12_RESOURCE_STATES kDesiredState = D3D12_RESOURCE_STATE_COPY_DEST;
1013                        D3D12_RESOURCE_STATES resourceState = kDesiredState;
1014                        s_D3D12->GetResourceState(resource, &resourceState); // Get resource state as it will be after all command lists Unity queued before this plugin call execute.
1015                        if (resourceState != kDesiredState)
1016                        {
1017                                D3D12_RESOURCE_BARRIER barrierDesc = {};
1018                                barrierDesc.Type = D3D12_RESOURCE_BARRIER_TYPE_TRANSITION;
1019                                barrierDesc.Transition.pResource = resource;
1020                                barrierDesc.Transition.Subresource = D3D12_RESOURCE_BARRIER_ALL_SUBRESOURCES;
1021                                barrierDesc.Transition.StateBefore = resourceState;
1022                                barrierDesc.Transition.StateAfter = kDesiredState;
1023                                s_D3D12CmdList->ResourceBarrier(1, &barrierDesc);
1024                                s_D3D12->SetResourceState(resource, kDesiredState); // Set resource state as it will be after this command list is executed.
1025                        }
1026
1027                        s_D3D12CmdList->CopyTextureRegion(&dstLoc, 0, 0, 0, &srcLoc, nullptr);
1028
1029                        // Execute the command list
1030                        s_D3D12CmdList->Close();
1031                        ID3D12CommandList* lists[1] = { s_D3D12CmdList };
1032                        queue->ExecuteCommandLists(1, lists);
1033                }
1034
1035                // Insert fence
1036                ++s_D3D12FenceValue;
1037                queue->Signal(s_D3D12Fence, s_D3D12FenceValue);
1038        }
1039        #endif
1040
1041
1042
1043        #if SUPPORT_OPENGL_LEGACY
1044        // OpenGL 2 legacy case (deprecated)
1045        if (s_DeviceType == kUnityGfxRendererOpenGL)
1046        {
1047                // Transformation matrices
1048                glMatrixMode (GL_MODELVIEW);
1049                glLoadMatrixf (worldMatrix);
1050                glMatrixMode (GL_PROJECTION);
1051                // Tweak the projection matrix a bit to make it match what identity
1052                // projection would do in D3D case.
1053                projectionMatrix[10] = 2.0f;
1054                projectionMatrix[14] = -1.0f;
1055                glLoadMatrixf (projectionMatrix);
1056
1057                // Vertex layout
1058                glVertexPointer (3, GL_FLOAT, sizeof(verts[0]), &verts[0].x);
1059                glEnableClientState (GL_VERTEX_ARRAY);
1060                glColorPointer (4, GL_UNSIGNED_BYTE, sizeof(verts[0]), &verts[0].color);
1061                glEnableClientState (GL_COLOR_ARRAY);
1062
1063                // Draw!
1064                glDrawArrays (GL_TRIANGLES, 0, 3);
1065
1066                // update native texture from code
1067                if (g_TexturePointer)
1068                {
1069                        GLuint gltex = (GLuint)(size_t)(g_TexturePointer);
1070                        glBindTexture (GL_TEXTURE_2D, gltex);
1071                        int texWidth, texHeight;
1072                        glGetTexLevelParameteriv (GL_TEXTURE_2D, 0, GL_TEXTURE_WIDTH, &texWidth);
1073                        glGetTexLevelParameteriv (GL_TEXTURE_2D, 0, GL_TEXTURE_HEIGHT, &texHeight);
1074
1075                        unsigned char* data = new unsigned char[texWidth*texHeight*4];
1076                        FillTextureFromCode (texWidth, texHeight, texHeight*4, data);
1077                        glTexSubImage2D (GL_TEXTURE_2D, 0, 0, 0, texWidth, texHeight, GL_RGBA, GL_UNSIGNED_BYTE, data);
1078                        delete[] data;
1079                }
1080        }
1081        #endif
1082       
1083       
1084       
1085        #if SUPPORT_OPENGL_UNIFIED
1086        #define BUFFER_OFFSET(i) ((char *)NULL + (i))
1087
1088        // OpenGL ES / core case
1089        if (s_DeviceType == kUnityGfxRendererOpenGLES20 ||
1090                s_DeviceType == kUnityGfxRendererOpenGLES30 ||
1091                s_DeviceType == kUnityGfxRendererOpenGLCore)
1092        {
1093                assert(glGetError() == GL_NO_ERROR); // Make sure no OpenGL error happen before starting rendering
1094
1095                // Tweak the projection matrix a bit to make it match what identity projection would do in D3D case.
1096                projectionMatrix[10] = 2.0f;
1097                projectionMatrix[14] = -1.0f;
1098
1099                glUseProgram(g_Program);
1100                glUniformMatrix4fv(g_WorldMatrixUniformIndex, 1, GL_FALSE, worldMatrix);
1101                glUniformMatrix4fv(g_ProjMatrixUniformIndex, 1, GL_FALSE, projectionMatrix);
1102
1103#if SUPPORT_OPENGL_CORE
1104                if (s_DeviceType == kUnityGfxRendererOpenGLCore)
1105                {
1106                        glGenVertexArrays(1, &g_VertexArray);
1107                        glBindVertexArray(g_VertexArray);
1108                }
1109#endif
1110
1111                glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
1112                glBindBuffer(GL_ARRAY_BUFFER, g_ArrayBuffer);
1113                glBufferSubData(GL_ARRAY_BUFFER, 0, sizeof(MyVertex) * 3, &verts[0].x);
1114
1115                glEnableVertexAttribArray(ATTRIB_POSITION);
1116                glVertexAttribPointer(ATTRIB_POSITION, 3, GL_FLOAT, GL_FALSE, sizeof(MyVertex), BUFFER_OFFSET(0));
1117
1118                glEnableVertexAttribArray(ATTRIB_COLOR);
1119                glVertexAttribPointer(ATTRIB_COLOR, 4, GL_UNSIGNED_BYTE, GL_TRUE, sizeof(MyVertex), BUFFER_OFFSET(sizeof(float) * 3));
1120
1121                glDrawArrays(GL_TRIANGLES, 0, 3);
1122
1123                // update native texture from code
1124                if (g_TexturePointer)
1125                {
1126                        GLuint gltex = (GLuint)(size_t)(g_TexturePointer);
1127                        glBindTexture(GL_TEXTURE_2D, gltex);
1128                        // The script only pass width and height with OpenGL ES on mobile
1129#if SUPPORT_OPENGL_CORE
1130                        if (s_DeviceType == kUnityGfxRendererOpenGLCore)
1131                        {
1132                                glGetTexLevelParameteriv (GL_TEXTURE_2D, 0, GL_TEXTURE_WIDTH, &g_TexWidth);
1133                                glGetTexLevelParameteriv (GL_TEXTURE_2D, 0, GL_TEXTURE_HEIGHT, &g_TexHeight);
1134                        }
1135#endif
1136
1137                        unsigned char* data = new unsigned char[g_TexWidth*g_TexHeight*4];
1138                        FillTextureFromCode(g_TexWidth, g_TexHeight, g_TexHeight*4, data);
1139                        glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, g_TexWidth, g_TexHeight, GL_RGBA, GL_UNSIGNED_BYTE, data);
1140                        delete[] data;
1141                }
1142
1143#if SUPPORT_OPENGL_CORE
1144                if (s_DeviceType == kUnityGfxRendererOpenGLCore)
1145                {
1146                        glDeleteVertexArrays(1, &g_VertexArray);
1147                }
1148#endif
1149
1150                assert(glGetError() == GL_NO_ERROR);
1151        }
1152        #endif
1153}
Note: See TracBrowser for help on using the repository browser.