1 //
2 //   Copyright 2013 Pixar
3 //
4 //   Licensed under the Apache License, Version 2.0 (the "Apache License")
5 //   with the following modification; you may not use this file except in
6 //   compliance with the Apache License and the following modification to it:
7 //   Section 6. Trademarks. is deleted and replaced with:
8 //
9 //   6. Trademarks. This License does not grant permission to use the trade
10 //      names, trademarks, service marks, or product names of the Licensor
11 //      and its affiliates, except as required to comply with Section 4(c) of
12 //      the License and to reproduce the content of the NOTICE file.
13 //
14 //   You may obtain a copy of the Apache License at
15 //
16 //       http://www.apache.org/licenses/LICENSE-2.0
17 //
18 //   Unless required by applicable law or agreed to in writing, software
19 //   distributed under the Apache License with the above modification is
20 //   distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
21 //   KIND, either express or implied. See the Apache License for the specific
22 //   language governing permissions and limitations under the Apache License.
23 //
24 
25 #include <D3D11.h>
26 #include <D3Dcompiler.h>
27 
28 #include <opensubdiv/far/error.h>
29 
30 #include <opensubdiv/osd/cpuD3D11VertexBuffer.h>
31 #include <opensubdiv/osd/cpuEvaluator.h>
32 
33 #ifdef OPENSUBDIV_HAS_OPENMP
34     #include <opensubdiv/osd/ompEvaluator.h>
35 #endif
36 
37 #ifdef OPENSUBDIV_HAS_TBB
38     #include <opensubdiv/osd/tbbEvaluator.h>
39 #endif
40 
41 #ifdef OPENSUBDIV_HAS_OPENCL
42     #include <opensubdiv/osd/clD3D11VertexBuffer.h>
43     #include <opensubdiv/osd/clEvaluator.h>
44     #include "../common/clDeviceContext.h"
45     CLD3D11DeviceContext g_clDeviceContext;
46 #endif
47 
48 #ifdef OPENSUBDIV_HAS_CUDA
49     #include <opensubdiv/osd/cudaD3D11VertexBuffer.h>
50     #include <opensubdiv/osd/cudaEvaluator.h>
51     #include "../common/cudaDeviceContext.h"
52     CudaDeviceContext g_cudaDeviceContext;
53 #endif
54 
55 #include <opensubdiv/osd/d3d11VertexBuffer.h>
56 #include <opensubdiv/osd/d3d11ComputeEvaluator.h>
57 
58 #include <opensubdiv/osd/d3d11Mesh.h>
59 OpenSubdiv::Osd::D3D11MeshInterface *g_mesh;
60 
61 #include "./sky.h"
62 
63 #include "Ptexture.h"
64 #include "PtexUtils.h"
65 
66 #include "../../regression/common/arg_utils.h"
67 #include "../../regression/common/far_utils.h"
68 #include "../common/objAnim.h"
69 #include "../common/stopwatch.h"
70 #include "../common/simple_math.h"
71 #include "../common/d3d11Hud.h"
72 #include "../common/d3d11PtexMipmapTexture.h"
73 #include "../common/d3d11ShaderCache.h"
74 #include "../common/hdr_reader.h"
75 
76 #include <opensubdiv/osd/hlslPatchShaderSource.h>
77 static const char *g_shaderSource =
78 #include "shader.gen.h"
79 ;
80 
81 #include <algorithm>
82 #include <cfloat>
83 #include <fstream>
84 #include <string>
85 #include <iostream>
86 #include <iterator>
87 #include <sstream>
88 #include <vector>
89 
90 #define SAFE_RELEASE(p) { if(p) { (p)->Release(); (p)=NULL; } }
91 
92 enum KernelType { kCPU = 0,
93                   kOPENMP = 1,
94                   kTBB = 2,
95                   kCUDA = 3,
96                   kCL = 4,
97                   kDirectCompute = 5 };
98 
99 enum HudCheckBox { HUD_CB_ADAPTIVE,
100                    HUD_CB_DISPLAY_OCCLUSION,
101                    HUD_CB_DISPLAY_NORMALMAP,
102                    HUD_CB_DISPLAY_SPECULAR,
103                    HUD_CB_ANIMATE_VERTICES,
104                    HUD_CB_VIEW_LOD,
105                    HUD_CB_FRACTIONAL_SPACING,
106                    HUD_CB_PATCH_CULL,
107                    HUD_CB_IBL,
108                    HUD_CB_BLOOM,
109                    HUD_CB_SEAMLESS_MIPMAP,
110                    HUD_CB_FREEZE };
111 
112 enum HudRadioGroup { HUD_RB_KERNEL,
113                      HUD_RB_LEVEL,
114                      HUD_RB_SCHEME,
115                      HUD_RB_WIRE,
116                      HUD_RB_COLOR,
117                      HUD_RB_DISPLACEMENT,
118                      HUD_RB_NORMAL };
119 
120 enum DisplayType { DISPLAY_WIRE,
121                    DISPLAY_SHADED,
122                    DISPLAY_WIRE_ON_SHADED };
123 
124 enum ColorType { COLOR_NONE,
125                  COLOR_PTEX_NEAREST,
126                  COLOR_PTEX_HW_BILINEAR,
127                  COLOR_PTEX_BILINEAR,
128                  COLOR_PTEX_BIQUADRATIC,
129                  COLOR_PATCHTYPE,
130                  COLOR_PATCHCOORD,
131                  COLOR_NORMAL };
132 
133 enum DisplacementType { DISPLACEMENT_NONE,
134                         DISPLACEMENT_HW_BILINEAR,
135                         DISPLACEMENT_BILINEAR,
136                         DISPLACEMENT_BIQUADRATIC };
137 
138 enum NormalType { NORMAL_SURFACE,
139                   NORMAL_FACET,
140                   NORMAL_HW_SCREENSPACE,
141                   NORMAL_SCREENSPACE,
142                   NORMAL_BIQUADRATIC,
143                   NORMAL_BIQUADRATIC_WG };
144 
145 //-----------------------------------------------------------------------------
146 int   g_frame = 0,
147       g_repeatCount = 0;
148 
149 // GUI variables
150 int   g_fullscreen = 0,
151       g_wire = DISPLAY_SHADED,
152       g_drawNormals = 0,
153       g_mbutton[3] = {0, 0, 0},
154       g_level = 2,
155       g_tessLevel = 2,
156       g_kernel = kCPU,
157       g_scheme = 0,
158       g_running = 1,
159       g_maxMipmapLevels = 10,
160       g_color = COLOR_PTEX_BILINEAR,
161       g_displacement = DISPLACEMENT_NONE,
162       g_normal = NORMAL_SURFACE;
163 
164 
165 float g_moveScale = 0.0f,
166       g_displacementScale = 1.0f,
167       g_mipmapBias = 0.0;
168 
169 bool  g_adaptive = true,
170       g_yup = false,
171       g_patchCull = true,
172       g_screenSpaceTess = true,
173       g_fractionalSpacing = true,
174       g_ibl = false,
175       g_bloom = false,
176       g_freeze = false;
177 
178 // ptex switch
179 bool  g_occlusion = false,
180       g_specular = false;
181 
182 bool g_seamless = true;
183 
184 // camera
185 float g_rotate[2] = {0, 0},
186       g_prev_x = 0,
187       g_prev_y = 0,
188       g_dolly = 5,
189       g_pan[2] = {0, 0},
190       g_center[3] = {0, 0, 0},
191       g_size = 0;
192 
193 
194 // viewport
195 int   g_width = 1024,
196       g_height = 1024;
197 
198 D3D11hud *g_hud = NULL;
199 
200 // performance
201 float g_cpuTime = 0;
202 float g_gpuTime = 0;
203 #define NUM_FPS_TIME_SAMPLES 6
204 float g_fpsTimeSamples[NUM_FPS_TIME_SAMPLES] = {0, 0, 0, 0, 0, 0};
205 int   g_currentFpsTimeSample = 0;
206 Stopwatch g_fpsTimer;
207 float g_animTime = 0;
208 
209 // geometry
210 std::vector<float> g_positions,
211                    g_normals;
212 
213 ObjAnim const * g_objAnim = 0;
214 
215 Sky * g_sky=0;
216 
217 D3D11PtexMipmapTexture * g_osdPTexImage = 0;
218 D3D11PtexMipmapTexture * g_osdPTexDisplacement = 0;
219 D3D11PtexMipmapTexture * g_osdPTexOcclusion = 0;
220 D3D11PtexMipmapTexture * g_osdPTexSpecular = 0;
221 const char * g_ptexColorFilename;
222 size_t g_ptexMemoryUsage = 0;
223 
224 ID3D11Device * g_pd3dDevice = NULL;
225 ID3D11DeviceContext * g_pd3dDeviceContext = NULL;
226 IDXGISwapChain * g_pSwapChain = NULL;
227 ID3D11RenderTargetView * g_pSwapChainRTV = NULL;
228 
229 ID3D11RasterizerState* g_pRasterizerState = NULL;
230 ID3D11InputLayout * g_pInputLayout = NULL;
231 ID3D11DepthStencilState * g_pDepthStencilState = NULL;
232 ID3D11Texture2D * g_pDepthStencilBuffer = NULL;
233 ID3D11Buffer * g_pcbPerFrame = NULL;
234 ID3D11Buffer * g_pcbTessellation = NULL;
235 ID3D11Buffer * g_pcbLighting = NULL;
236 ID3D11Buffer * g_pcbConfig = NULL;
237 ID3D11DepthStencilView * g_pDepthStencilView = NULL;
238 
239 ID3D11Texture2D * g_diffuseEnvironmentMap = NULL;
240 ID3D11ShaderResourceView * g_diffuseEnvironmentSRV = NULL;
241 
242 ID3D11Texture2D * g_specularEnvironmentMap = NULL;
243 ID3D11ShaderResourceView * g_specularEnvironmentSRV = NULL;
244 
245 ID3D11SamplerState * g_iblSampler = NULL;
246 
247 ID3D11Query * g_pipelineStatsQuery = NULL;
248 
249 bool g_bDone = false;
250 
251 //------------------------------------------------------------------------------
252 
253 static ID3D11Texture2D *
createHDRTexture(ID3D11Device * device,char const * hdrFile)254 createHDRTexture(ID3D11Device * device, char const * hdrFile) {
255 
256     HdrInfo info;
257     unsigned char * image = loadHdr(hdrFile, &info, /*convertToFloat=*/true);
258     if (image) {
259 
260         D3D11_TEXTURE2D_DESC texDesc;
261         ZeroMemory(&texDesc, sizeof(texDesc));
262         texDesc.Width = info.width;
263         texDesc.Height = info.height;
264         texDesc.MipLevels = 1;
265         texDesc.ArraySize = 1;
266         texDesc.Format = DXGI_FORMAT_R32G32B32A32_FLOAT;
267         texDesc.SampleDesc.Count = 1;
268         texDesc.SampleDesc.Quality = 0;
269         texDesc.Usage = D3D11_USAGE_DEFAULT;
270         texDesc.BindFlags =  D3D11_BIND_UNORDERED_ACCESS | D3D11_BIND_SHADER_RESOURCE;
271         texDesc.CPUAccessFlags = 0;
272         texDesc.MiscFlags = 0;
273 
274         D3D11_SUBRESOURCE_DATA subData;
275         subData.pSysMem = (void *)image;
276         subData.SysMemPitch = info.width * 4 * sizeof(float);
277 
278         ID3D11Texture2D * texture=0;
279         device->CreateTexture2D(&texDesc, &subData, &texture);
280 
281         free(image);
282         return texture;
283     }
284     return 0;
285 }
286 
287 //------------------------------------------------------------------------------
288 static void
calcNormals(OpenSubdiv::Far::TopologyRefiner * refiner,std::vector<float> const & pos,std::vector<float> & result)289 calcNormals(OpenSubdiv::Far::TopologyRefiner * refiner,
290     std::vector<float> const & pos, std::vector<float> & result ) {
291 
292     typedef OpenSubdiv::Far::ConstIndexArray IndexArray;
293 
294     // calc normal vectors
295     OpenSubdiv::Far::TopologyLevel const & refBaseLevel = refiner->GetLevel(0);
296 
297     int nverts = refBaseLevel.GetNumVertices(),
298         nfaces = refBaseLevel.GetNumFaces();
299 
300     for (int face = 0; face < nfaces; ++face) {
301 
302         IndexArray fverts = refBaseLevel.GetFaceVertices(face);
303 
304         float const * p0 = &pos[fverts[0]*3],
305                     * p1 = &pos[fverts[1]*3],
306                     * p2 = &pos[fverts[2]*3];
307 
308         float n[3];
309         cross(n, p0, p1, p2);
310 
311         for (int vert = 0; vert < fverts.size(); ++vert) {
312             int idx = fverts[vert] * 3;
313             result[idx  ] += n[0];
314             result[idx+1] += n[1];
315             result[idx+2] += n[2];
316         }
317     }
318     for (int i = 0; i < nverts; ++i)
319         normalize(&result[i*3]);
320 }
321 
322 //------------------------------------------------------------------------------
323 static void
updateGeom()324 updateGeom() {
325 
326     int nverts = (int)g_positions.size() / 3;
327 
328     if (g_moveScale && g_adaptive && g_objAnim) {
329 
330         // baked animation only works with adaptive for now
331         // (since non-adaptive requires normals)
332         // but we clear space in the buffer for normals since
333         // we do not have an easy shader variant with positions only
334         int numElements = 6; //g_adaptive ? 3 : 6;
335         std::vector<float> vertex(nverts*numElements, 0.0f);
336 
337         g_objAnim->InterpolatePositions(g_animTime, &vertex[0], numElements);
338 
339         g_mesh->UpdateVertexBuffer(&vertex[0], 0, nverts);
340 
341     } else {
342         std::vector<float> vertex;
343         vertex.reserve(nverts*6);
344 
345         const float *p = &g_positions[0];
346         const float *n = &g_normals[0];
347 
348         for (int i = 0; i < nverts; ++i) {
349             float move = g_size*0.005f*cosf(p[0]*100/g_size+g_frame*0.01f);
350             vertex.push_back(p[0]);
351             vertex.push_back(p[1]+g_moveScale*move);
352             vertex.push_back(p[2]);
353             p += 3;
354     //        if (g_adaptive == false)
355             {
356                 vertex.push_back(n[0]);
357                 vertex.push_back(n[1]);
358                 vertex.push_back(n[2]);
359                 n += 3;
360             }
361         }
362 
363         g_mesh->UpdateVertexBuffer(&vertex[0], 0, nverts);
364     }
365 
366     Stopwatch s;
367     s.Start();
368 
369     g_mesh->Refine();
370 
371     s.Stop();
372     g_cpuTime = float(s.GetElapsed() * 1000.0f);
373     s.Start();
374 
375     g_mesh->Synchronize();
376 
377     s.Stop();
378     g_gpuTime = float(s.GetElapsed() * 1000.0f);
379 }
380 
381 //-------------------------------------------------------------------------------
382 static void
fitFrame()383 fitFrame() {
384     g_pan[0] = g_pan[1] = 0;
385     g_dolly = g_size;
386 }
387 
388 //-------------------------------------------------------------------------------
389 Shape *
createPTexGeo(PtexTexture * r)390 createPTexGeo(PtexTexture * r) {
391 
392     PtexMetaData* meta = r->getMetaData();
393 
394     if (meta->numKeys() < 3) {
395         return NULL;
396     }
397 
398     float const * vp;
399     int const *vi, *vc;
400     int nvp, nvi, nvc;
401 
402     meta->getValue("PtexFaceVertCounts", vc, nvc);
403     if (nvc == 0) {
404         return NULL;
405     }
406     meta->getValue("PtexVertPositions", vp, nvp);
407     if (nvp == 0) {
408         return NULL;
409     }
410     meta->getValue("PtexFaceVertIndices", vi, nvi);
411     if (nvi == 0) {
412         return NULL;
413     }
414 
415     Shape * shape = new Shape;
416 
417     shape->scheme = kCatmark;
418 
419     shape->verts.resize(nvp);
420     for (int i=0; i<nvp; ++i) {
421         shape->verts[i] = vp[i];
422     }
423 
424     shape->nvertsPerFace.resize(nvc);
425     for (int i=0; i<nvc; ++i) {
426         shape->nvertsPerFace[i] = vc[i];
427     }
428 
429     shape->faceverts.resize(nvi);
430     for (int i=0; i<nvi; ++i) {
431         shape->faceverts[i] = vi[i];
432     }
433 
434     // compute model bounding
435     float min[3] = {vp[0], vp[1], vp[2]};
436     float max[3] = {vp[0], vp[1], vp[2]};
437     for (int i = 0; i < nvp/3; ++i) {
438         for (int j = 0; j < 3; ++j) {
439             float v = vp[i*3+j];
440             min[j] = std::min(min[j], v);
441             max[j] = std::max(max[j], v);
442         }
443     }
444 
445     g_size=0.0f;
446     for (int j = 0; j < 3; ++j) {
447         g_center[j] = (min[j] + max[j]) * 0.5f;
448         g_size += (max[j]-min[j])*(max[j]-min[j]);
449     }
450     g_size = sqrtf(g_size);
451 
452     return shape;
453 }
454 
455 //------------------------------------------------------------------------------
456 static const char *
getKernelName(int kernel)457 getKernelName(int kernel) {
458 
459     if (kernel == kCPU)
460         return "CPU";
461     else if (kernel == kOPENMP)
462         return "OpenMP";
463     else if (kernel == kTBB)
464         return "TBB";
465     else if (kernel == kCUDA)
466         return "Cuda";
467     else if (kernel == kCL)
468         return "OpenCL";
469     else if (kernel == kDirectCompute)
470         return "DirectCompute";
471     return "Unknown";
472 }
473 
474 //------------------------------------------------------------------------------
475 
476 union Effect {
477     struct {
478         unsigned int wire:2;
479         unsigned int color:3;
480         unsigned int displacement:2;
481         unsigned int normal:3;
482         int occlusion:1;
483         int specular:1;
484         int patchCull:1;
485         int screenSpaceTess:1;
486         int fractionalSpacing:1;
487         int ibl:1;
488         int seamless:1;
489     };
490     int value;
491 
operator <(const Effect & e) const492     bool operator < (const Effect &e) const {
493         return value < e.value;
494     }
495 };
496 
497 struct EffectDesc {
EffectDescEffectDesc498     EffectDesc(OpenSubdiv::Far::PatchDescriptor desc,
499                Effect effect) : desc(desc), effect(effect),
500                                 maxValence(0), numElements(0) { }
501 
502     OpenSubdiv::Far::PatchDescriptor desc;
503     Effect effect;
504     int maxValence;
505     int numElements;
506 
operator <EffectDesc507     bool operator < (const EffectDesc &e) const {
508         return desc < e.desc || (desc == e.desc &&
509               (maxValence < e.maxValence || ((maxValence == e.maxValence) &&
510               (effect < e.effect))));
511     }
512 };
513 
514 class ShaderCache : public D3D11ShaderCache<EffectDesc> {
515 public:
CreateDrawConfig(EffectDesc const & effectDesc)516     virtual D3D11DrawConfig *CreateDrawConfig(EffectDesc const &effectDesc) {
517         using namespace OpenSubdiv;
518 
519         D3D11DrawConfig *config = new D3D11DrawConfig();
520 
521         Far::PatchDescriptor::Type type = effectDesc.desc.GetType();
522 
523         // common defines
524         std::stringstream ss;
525 
526         if (type == Far::PatchDescriptor::QUADS) {
527             ss << "#define PRIM_QUAD\n";
528         } else {
529             ss << "#define PRIM_TRI\n";
530         }
531 
532         // OSD tessellation controls
533         if (effectDesc.effect.screenSpaceTess) {
534             ss << "#define OSD_ENABLE_SCREENSPACE_TESSELLATION\n";
535         }
536         if (effectDesc.effect.fractionalSpacing) {
537             ss << "#define OSD_FRACTIONAL_ODD_SPACING\n";
538         }
539         if (effectDesc.effect.patchCull) {
540             ss << "#define OSD_ENABLE_PATCH_CULL\n";
541         }
542 
543        // add ptex functions
544         ss << D3D11PtexMipmapTexture::GetShaderSource();
545 
546         // -------------------------------------------------------------
547         // display styles
548         // -------------------------------------------------------------
549 
550         // mipmap
551         if (effectDesc.effect.seamless) {
552             ss << "#define SEAMLESS_MIPMAP\n";
553         }
554 
555         //  wire
556         if (effectDesc.effect.wire == 0) {
557             ss << "#define GEOMETRY_OUT_WIRE\n";
558         } else if (effectDesc.effect.wire == 1) {
559             ss << "#define GEOMETRY_OUT_FILL\n";
560         } else if (effectDesc.effect.wire == 2) {
561             ss << "#define GEOMETRY_OUT_LINE\n";
562         }
563 
564         //  color
565         switch(effectDesc.effect.color) {
566         case COLOR_NONE:
567             break;
568         case COLOR_PTEX_NEAREST:
569             ss << "#define COLOR_PTEX_NEAREST\n";
570             break;
571         case COLOR_PTEX_HW_BILINEAR:
572             ss << "#define COLOR_PTEX_HW_BILINEAR\n";
573             break;
574         case COLOR_PTEX_BILINEAR:
575             ss << "#define COLOR_PTEX_BILINEAR\n";
576             break;
577         case COLOR_PTEX_BIQUADRATIC:
578             ss << "#define COLOR_PTEX_BIQUADRATIC\n";
579             break;
580         case COLOR_PATCHTYPE:
581             ss << "#define COLOR_PATCHTYPE\n";
582             break;
583         case COLOR_PATCHCOORD:
584             ss << "#define COLOR_PATCHCOORD\n";
585             break;
586         case COLOR_NORMAL:
587             ss << "#define COLOR_NORMAL\n";
588             break;
589         }
590 
591         // displacement
592         switch (effectDesc.effect.displacement) {
593         case DISPLACEMENT_NONE:
594             break;
595         case DISPLACEMENT_HW_BILINEAR:
596             ss << "#define DISPLACEMENT_HW_BILINEAR\n";
597             break;
598         case DISPLACEMENT_BILINEAR:
599             ss << "#define DISPLACEMENT_BILINEAR\n";
600             break;
601         case DISPLACEMENT_BIQUADRATIC:
602             ss << "#define DISPLACEMENT_BIQUADRATIC\n";
603             break;
604         }
605 
606         // normal
607         switch (effectDesc.effect.normal) {
608         case NORMAL_FACET:
609             ss << "#define NORMAL_FACET\n";
610             break;
611         case NORMAL_HW_SCREENSPACE:
612             ss << "#define NORMAL_HW_SCREENSPACE\n";
613             break;
614         case NORMAL_SCREENSPACE:
615             ss << "#define NORMAL_SCREENSPACE\n";
616             break;
617         case NORMAL_BIQUADRATIC:
618             ss << "#define NORMAL_BIQUADRATIC\n";
619             break;
620         case NORMAL_BIQUADRATIC_WG:
621             ss << "#define OSD_COMPUTE_NORMAL_DERIVATIVES\n";
622             ss << "#define NORMAL_BIQUADRATIC_WG\n";
623             break;
624         }
625 
626         // occlusion
627         if (effectDesc.effect.occlusion)
628             ss << "#define USE_PTEX_OCCLUSION\n";
629 
630         // specular
631         if (effectDesc.effect.specular)
632             ss << "#define USE_PTEX_SPECULAR\n";
633 
634         // IBL
635         if (effectDesc.effect.ibl)
636             ss << "#define USE_IBL\n";
637 
638         // need for patch color-coding : we need these defines in the fragment shader
639         if (type == Far::PatchDescriptor::GREGORY) {
640             ss << "#define OSD_PATCH_GREGORY\n";
641         } else if (type == Far::PatchDescriptor::GREGORY_BOUNDARY) {
642             ss << "#define OSD_PATCH_GREGORY_BOUNDARY\n";
643         } else if (type == Far::PatchDescriptor::GREGORY_BASIS) {
644             ss << "#define OSD_PATCH_GREGORY_BASIS\n";
645         }
646 
647         // include osd PatchCommon
648         ss << Osd::HLSLPatchShaderSource::GetCommonShaderSource();
649         std::string common = ss.str();
650         ss.str("");
651 
652         // input layout
653         const D3D11_INPUT_ELEMENT_DESC hInElementDesc[] = {
654             { "POSITION", 0, DXGI_FORMAT_R32G32B32_FLOAT, 0, 0, D3D11_INPUT_PER_VERTEX_DATA, 0 },
655             { "NORMAL", 0, DXGI_FORMAT_R32G32B32_FLOAT, 0, 4*3, D3D11_INPUT_PER_VERTEX_DATA, 0 }
656         };
657 
658         // vertex shader
659         ss << common
660            << g_shaderSource
661            << Osd::HLSLPatchShaderSource::GetVertexShaderSource(type);
662         if (effectDesc.desc.IsAdaptive()) {
663             config->CompileVertexShader("vs_5_0", "vs_main_patches", ss.str(),
664                                         &g_pInputLayout,
665                                         hInElementDesc,
666                                         ARRAYSIZE(hInElementDesc),
667                                         g_pd3dDevice);
668         } else {
669             config->CompileVertexShader("vs_5_0", "vs_main",
670                                         ss.str(),
671                                         &g_pInputLayout,
672                                         hInElementDesc,
673                                         ARRAYSIZE(hInElementDesc),
674                                         g_pd3dDevice);
675         }
676         ss.str("");
677 
678 
679         if (effectDesc.desc.IsAdaptive()) {
680             // hull shader
681             ss << common
682                << g_shaderSource
683                << Osd::HLSLPatchShaderSource::GetHullShaderSource(type);
684             config->CompileHullShader("hs_5_0", "hs_main_patches", ss.str(),
685                                       g_pd3dDevice);
686             ss.str("");
687 
688             // domain shader
689             ss << common
690                << g_shaderSource
691                << Osd::HLSLPatchShaderSource::GetDomainShaderSource(type);
692             config->CompileDomainShader("ds_5_0", "ds_main_patches", ss.str(),
693                                         g_pd3dDevice);
694             ss.str("");
695         }
696 
697         // geometry shader
698         ss << common
699            << g_shaderSource;
700         config->CompileGeometryShader("gs_5_0", "gs_main", ss.str(),
701                                       g_pd3dDevice);
702         ss.str("");
703 
704         // pixel shader
705         ss << common
706            << g_shaderSource;
707         config->CompilePixelShader("ps_5_0", "ps_main", ss.str(),
708                                    g_pd3dDevice);
709         ss.str("");
710 
711         return config;
712     };
713 };
714 
715 ShaderCache g_shaderCache;
716 
717 //------------------------------------------------------------------------------
718 D3D11PtexMipmapTexture *
createPtex(const char * filename,int memLimit)719 createPtex(const char *filename, int memLimit) {
720 
721     Ptex::String ptexError;
722     printf("Loading ptex : %s\n", filename);
723 
724 #define USE_PTEX_CACHE
725 #define PTEX_CACHE_SIZE (512*1024*1024)
726 
727 #ifdef USE_PTEX_CACHE
728     PtexCache *cache = PtexCache::create(1, PTEX_CACHE_SIZE);
729     PtexTexture *ptex = cache->get(filename, ptexError);
730 #else
731     PtexTexture *ptex = PtexTexture::open(filename, ptexError, true);
732 #endif
733 
734     if (ptex == NULL) {
735         printf("Error in reading %s\n", filename);
736         exit(1);
737     }
738 
739     size_t targetMemory = memLimit * 1024 * 1024; // MB
740 
741     D3D11PtexMipmapTexture *osdPtex = D3D11PtexMipmapTexture::Create(
742         g_pd3dDeviceContext, ptex, g_maxMipmapLevels, targetMemory);
743 
744     ptex->release();
745 
746 #ifdef USE_PTEX_CACHE
747     cache->release();
748 #endif
749 
750     return osdPtex;
751 }
752 
753 //------------------------------------------------------------------------------
754 void
createOsdMesh(int level,int kernel)755 createOsdMesh(int level, int kernel) {
756 
757     using namespace OpenSubdiv;
758     Ptex::String ptexError;
759     PtexTexture *ptexColor = PtexTexture::open(g_ptexColorFilename, ptexError, true);
760     if (ptexColor == NULL) {
761         printf("Error in reading %s\n", g_ptexColorFilename);
762         exit(1);
763     }
764 
765     // generate Hbr representation from ptex
766     Shape * shape = createPTexGeo(ptexColor);
767     if (!shape) {
768         return;
769     }
770 
771     g_positions=shape->verts;
772 
773     typedef OpenSubdiv::Far::ConstIndexArray IndexArray;
774 
775     // create Far mesh (topology)
776     OpenSubdiv::Sdc::SchemeType sdctype = GetSdcType(*shape);
777     OpenSubdiv::Sdc::Options sdcoptions = GetSdcOptions(*shape);
778 
779     OpenSubdiv::Far::TopologyRefiner * refiner =
780         OpenSubdiv::Far::TopologyRefinerFactory<Shape>::Create(*shape,
781             OpenSubdiv::Far::TopologyRefinerFactory<Shape>::Options(sdctype, sdcoptions));
782 
783     // save coarse topology (used for coarse mesh drawing)
784     OpenSubdiv::Far::TopologyLevel const & refBaseLevel = refiner->GetLevel(0);
785 
786     // create cage edge index
787     int nedges = refBaseLevel.GetNumEdges();
788     std::vector<int> edgeIndices(nedges*2);
789     for(int i=0; i<nedges; ++i) {
790         IndexArray verts = refBaseLevel.GetEdgeVertices(i);
791         edgeIndices[i*2  ]=verts[0];
792         edgeIndices[i*2+1]=verts[1];
793     }
794 
795     delete shape;
796 
797     g_normals.resize(g_positions.size(), 0.0f);
798     calcNormals(refiner, g_positions, g_normals);
799 
800     delete g_mesh;
801     g_mesh = NULL;
802 
803     // Adaptive refinement currently supported only for catmull-clark scheme
804     bool doAdaptive = (g_adaptive != 0 && g_scheme == 0);
805 
806     OpenSubdiv::Osd::MeshBitset bits;
807     bits.set(OpenSubdiv::Osd::MeshAdaptive, doAdaptive);
808     bits.set(OpenSubdiv::Osd::MeshEndCapGregoryBasis, true);
809 
810     int numVertexElements = 6; //g_adaptive ? 3 : 6;
811     int numVaryingElements = 0;
812 
813     if (g_kernel == kCPU) {
814         g_mesh = new Osd::Mesh<Osd::CpuD3D11VertexBuffer,
815                                Far::StencilTable,
816                                Osd::CpuEvaluator,
817                                Osd::D3D11PatchTable,
818                                ID3D11DeviceContext>(
819                                    refiner,
820                                    numVertexElements,
821                                    numVaryingElements,
822                                    level, bits, NULL, g_pd3dDeviceContext);
823 
824 #ifdef OPENSUBDIV_HAS_OPENMP
825     } else if (kernel == kOPENMP) {
826         g_mesh = new Osd::Mesh<Osd::CpuD3D11VertexBuffer,
827                                Far::StencilTable,
828                                Osd::OmpEvaluator,
829                                Osd::D3D11PatchTable,
830                                ID3D11DeviceContext>(
831                                    refiner,
832                                    numVertexElements,
833                                    numVaryingElements,
834                                    level, bits, NULL, g_pd3dDeviceContext);
835 #endif
836 #ifdef OPENSUBDIV_HAS_TBB
837     } else if (kernel == kTBB) {
838         g_mesh = new Osd::Mesh<Osd::CpuD3D11VertexBuffer,
839                                Far::StencilTable,
840                                Osd::TbbEvaluator,
841                                Osd::D3D11PatchTable,
842                                ID3D11DeviceContext>(
843                                    refiner,
844                                    numVertexElements,
845                                    numVaryingElements,
846                                    level, bits, NULL, g_pd3dDeviceContext);
847 #endif
848 #ifdef OPENSUBDIV_HAS_OPENCL
849     } else if(kernel == kCL) {
850         static Osd::EvaluatorCacheT<Osd::CLEvaluator> clEvaluatorCache;
851         g_mesh = new Osd::Mesh<Osd::CLD3D11VertexBuffer,
852                                Osd::CLStencilTable,
853                                Osd::CLEvaluator,
854                                Osd::D3D11PatchTable,
855                                CLD3D11DeviceContext>(
856                                    refiner,
857                                    numVertexElements,
858                                    numVaryingElements,
859                                    level, bits,
860                                    &clEvaluatorCache,
861                                    &g_clDeviceContext);
862 #endif
863 #ifdef OPENSUBDIV_HAS_CUDA
864     } else if (g_kernel == kCUDA) {
865         g_mesh = new Osd::Mesh<Osd::CudaD3D11VertexBuffer,
866                                Osd::CudaStencilTable,
867                                Osd::CudaEvaluator,
868                                Osd::D3D11PatchTable,
869                                ID3D11DeviceContext>(
870                                    refiner,
871                                    numVertexElements,
872                                    numVaryingElements,
873                                    level, bits, NULL, g_pd3dDeviceContext);
874 #endif
875     } else if (g_kernel == kDirectCompute) {
876         static Osd::EvaluatorCacheT<Osd::D3D11ComputeEvaluator> d3d11ComputeEvaluatorCache;
877         g_mesh = new Osd::Mesh<Osd::D3D11VertexBuffer,
878                                Osd::D3D11StencilTable,
879                                Osd::D3D11ComputeEvaluator,
880                                Osd::D3D11PatchTable,
881                                ID3D11DeviceContext>(
882                                    refiner,
883                                    numVertexElements,
884                                    numVaryingElements,
885                                    level, bits,
886                                    &d3d11ComputeEvaluatorCache,
887                                    g_pd3dDeviceContext);
888     } else {
889         printf("Unsupported kernel %s\n", getKernelName(kernel));
890     }
891 
892     updateGeom();
893 }
894 
895 //------------------------------------------------------------------------------
896 static void
bindProgram(Effect effect,OpenSubdiv::Osd::PatchArray const & patch)897 bindProgram(Effect effect, OpenSubdiv::Osd::PatchArray const & patch) {
898 
899     EffectDesc effectDesc(patch.GetDescriptor(), effect);
900 
901     D3D11DrawConfig *config = g_shaderCache.GetDrawConfig(effectDesc);
902 
903     assert(g_pInputLayout);
904 
905     // Update transform state
906     {
907         __declspec(align(16))
908         struct CB_PER_FRAME_CONSTANTS
909         {
910             float ModelViewMatrix[16];
911             float ProjectionMatrix[16];
912             float ModelViewProjectionMatrix[16];
913             float ModelViewInverseMatrix[16];
914         };
915 
916         if (! g_pcbPerFrame) {
917             D3D11_BUFFER_DESC cbDesc;
918             ZeroMemory(&cbDesc, sizeof(cbDesc));
919             cbDesc.Usage = D3D11_USAGE_DYNAMIC;
920             cbDesc.BindFlags = D3D11_BIND_CONSTANT_BUFFER;
921             cbDesc.CPUAccessFlags = D3D11_CPU_ACCESS_WRITE;
922             cbDesc.MiscFlags = 0;
923             cbDesc.ByteWidth = sizeof(CB_PER_FRAME_CONSTANTS);
924             g_pd3dDevice->CreateBuffer(&cbDesc, NULL, &g_pcbPerFrame);
925         }
926         assert(g_pcbPerFrame);
927 
928         D3D11_MAPPED_SUBRESOURCE MappedResource;
929         g_pd3dDeviceContext->Map(g_pcbPerFrame, 0, D3D11_MAP_WRITE_DISCARD, 0, &MappedResource);
930         CB_PER_FRAME_CONSTANTS* pData = ( CB_PER_FRAME_CONSTANTS* )MappedResource.pData;
931 
932         float aspect = (g_height > 0) ? (float)g_width / g_height : 1.0f;
933         identity(pData->ModelViewMatrix);
934         translate(pData->ModelViewMatrix, -g_pan[0], -g_pan[1], -g_dolly);
935         rotate(pData->ModelViewMatrix, g_rotate[1], 1, 0, 0);
936         rotate(pData->ModelViewMatrix, g_rotate[0], 0, 1, 0);
937         if (!g_yup) {
938             rotate(pData->ModelViewMatrix, -90, 1, 0, 0);
939         }
940         translate(pData->ModelViewMatrix, -g_center[0], -g_center[1], -g_center[2]);
941 
942         identity(pData->ProjectionMatrix);
943         perspective(pData->ProjectionMatrix, 45.0, aspect, g_size*0.001f, g_size+g_dolly);
944         multMatrix(pData->ModelViewProjectionMatrix,
945                    pData->ModelViewMatrix,
946                    pData->ProjectionMatrix);
947         inverseMatrix(pData->ModelViewInverseMatrix,
948                       pData->ModelViewMatrix);
949         g_pd3dDeviceContext->Unmap( g_pcbPerFrame, 0 );
950     }
951 
952     // Update tessellation state
953     {
954         __declspec(align(16))
955         struct Tessellation {
956             float TessLevel;
957             int PrimitiveIdBase;
958         };
959 
960         if (! g_pcbTessellation) {
961             D3D11_BUFFER_DESC cbDesc;
962             ZeroMemory(&cbDesc, sizeof(cbDesc));
963             cbDesc.Usage = D3D11_USAGE_DYNAMIC;
964             cbDesc.BindFlags = D3D11_BIND_CONSTANT_BUFFER;
965             cbDesc.CPUAccessFlags = D3D11_CPU_ACCESS_WRITE;
966             cbDesc.MiscFlags = 0;
967             cbDesc.ByteWidth = sizeof(Tessellation);
968             g_pd3dDevice->CreateBuffer(&cbDesc, NULL, &g_pcbTessellation);
969         }
970         assert(g_pcbTessellation);
971 
972         D3D11_MAPPED_SUBRESOURCE MappedResource;
973         g_pd3dDeviceContext->Map(g_pcbTessellation, 0, D3D11_MAP_WRITE_DISCARD, 0, &MappedResource);
974         Tessellation * pData = ( Tessellation* )MappedResource.pData;
975 
976         pData->TessLevel = static_cast<float>(1 << g_tessLevel);
977         pData->PrimitiveIdBase = patch.GetPrimitiveIdBase();
978 
979         g_pd3dDeviceContext->Unmap( g_pcbTessellation, 0 );
980     }
981 
982     // Update config state
983     {
984         __declspec(align(16))
985             struct Config {
986                 float displacementScale;
987                 float mipmapBias;
988             };
989 
990         if (! g_pcbConfig) {
991             D3D11_BUFFER_DESC cbDesc;
992             ZeroMemory(&cbDesc, sizeof(cbDesc));
993             cbDesc.Usage = D3D11_USAGE_DYNAMIC;
994             cbDesc.BindFlags = D3D11_BIND_CONSTANT_BUFFER;
995             cbDesc.CPUAccessFlags = D3D11_CPU_ACCESS_WRITE;
996             cbDesc.MiscFlags = 0;
997             cbDesc.ByteWidth = sizeof(Config);
998             g_pd3dDevice->CreateBuffer(&cbDesc, NULL, &g_pcbConfig);
999         }
1000         assert(g_pcbConfig);
1001 
1002         D3D11_MAPPED_SUBRESOURCE MappedResource;
1003         g_pd3dDeviceContext->Map(g_pcbConfig, 0, D3D11_MAP_WRITE_DISCARD, 0, &MappedResource);
1004         Config * pData = ( Config* )MappedResource.pData;
1005 
1006         pData->displacementScale = g_displacementScale;
1007         pData->mipmapBias = g_mipmapBias;
1008 
1009         g_pd3dDeviceContext->Unmap( g_pcbConfig, 0 );
1010     }
1011 
1012     g_pd3dDeviceContext->IASetInputLayout(g_pInputLayout);
1013 
1014     g_pd3dDeviceContext->VSSetShader(config->GetVertexShader(), NULL, 0);
1015     g_pd3dDeviceContext->VSSetConstantBuffers(0, 1, &g_pcbPerFrame);
1016     g_pd3dDeviceContext->HSSetShader(config->GetHullShader(), NULL, 0);
1017     g_pd3dDeviceContext->HSSetConstantBuffers(0, 1, &g_pcbPerFrame);
1018     g_pd3dDeviceContext->HSSetConstantBuffers(1, 1, &g_pcbTessellation);
1019     g_pd3dDeviceContext->DSSetShader(config->GetDomainShader(), NULL, 0);
1020     g_pd3dDeviceContext->DSSetConstantBuffers(0, 1, &g_pcbPerFrame);
1021     g_pd3dDeviceContext->DSSetConstantBuffers(3, 1, &g_pcbConfig);
1022     g_pd3dDeviceContext->GSSetShader(config->GetGeometryShader(), NULL, 0);
1023     g_pd3dDeviceContext->GSSetConstantBuffers(0, 1, &g_pcbPerFrame);
1024     g_pd3dDeviceContext->PSSetShader(config->GetPixelShader(), NULL, 0);
1025     g_pd3dDeviceContext->PSSetConstantBuffers(0, 1, &g_pcbPerFrame);
1026     g_pd3dDeviceContext->PSSetConstantBuffers(2, 1, &g_pcbLighting);
1027     g_pd3dDeviceContext->PSSetConstantBuffers(3, 1, &g_pcbConfig);
1028 
1029     ID3D11ShaderResourceView *srv = g_mesh->GetPatchTable()->GetPatchParamSRV();
1030     if (srv) {
1031         g_pd3dDeviceContext->HSSetShaderResources(0, 1, &srv);
1032         g_pd3dDeviceContext->DSSetShaderResources(0, 1, &srv);
1033         g_pd3dDeviceContext->GSSetShaderResources(0, 1, &srv);
1034         g_pd3dDeviceContext->PSSetShaderResources(0, 1, &srv);
1035     }
1036 
1037     g_pd3dDeviceContext->PSSetShaderResources(4, 1, g_osdPTexImage->GetTexelsSRV());
1038     g_pd3dDeviceContext->PSSetShaderResources(5, 1, g_osdPTexImage->GetLayoutSRV());
1039 
1040     if (g_osdPTexDisplacement) {
1041         g_pd3dDeviceContext->DSSetShaderResources(6, 1, g_osdPTexDisplacement->GetTexelsSRV());
1042         g_pd3dDeviceContext->DSSetShaderResources(7, 1, g_osdPTexDisplacement->GetLayoutSRV());
1043         g_pd3dDeviceContext->PSSetShaderResources(6, 1, g_osdPTexDisplacement->GetTexelsSRV());
1044         g_pd3dDeviceContext->PSSetShaderResources(7, 1, g_osdPTexDisplacement->GetLayoutSRV());
1045     }
1046 
1047     if (g_osdPTexOcclusion) {
1048         g_pd3dDeviceContext->PSSetShaderResources(8, 1, g_osdPTexOcclusion->GetTexelsSRV());
1049         g_pd3dDeviceContext->PSSetShaderResources(9, 1, g_osdPTexOcclusion->GetLayoutSRV());
1050     }
1051 
1052     if (g_osdPTexSpecular) {
1053         g_pd3dDeviceContext->PSSetShaderResources(10, 1, g_osdPTexSpecular->GetTexelsSRV());
1054         g_pd3dDeviceContext->PSSetShaderResources(11, 1, g_osdPTexSpecular->GetLayoutSRV());
1055     }
1056 
1057     if (g_ibl) {
1058         if (g_diffuseEnvironmentMap) {
1059             g_pd3dDeviceContext->PSSetShaderResources(12, 1, &g_diffuseEnvironmentSRV);
1060 
1061         }
1062         if (g_specularEnvironmentMap) {
1063             g_pd3dDeviceContext->PSSetShaderResources(13, 1, &g_specularEnvironmentSRV);
1064 
1065         }
1066         assert(g_iblSampler);
1067         g_pd3dDeviceContext->PSSetSamplers(0, 1, &g_iblSampler);
1068     }
1069 }
1070 
1071 //------------------------------------------------------------------------------
1072 static void
drawModel()1073 drawModel() {
1074 
1075     ID3D11Buffer *buffer = g_mesh->BindVertexBuffer();
1076     assert(buffer);
1077 
1078     UINT hStrides = 6*sizeof(float);
1079     UINT hOffsets = 0;
1080     g_pd3dDeviceContext->IASetVertexBuffers(0, 1, &buffer, &hStrides, &hOffsets);
1081 
1082     OpenSubdiv::Osd::PatchArrayVector const & patches =
1083         g_mesh->GetPatchTable()->GetPatchArrays();
1084 
1085     g_pd3dDeviceContext->IASetIndexBuffer(
1086         g_mesh->GetPatchTable()->GetPatchIndexBuffer(),
1087         DXGI_FORMAT_R32_UINT, 0);
1088 
1089     // patch drawing
1090     for (int i = 0; i < (int)patches.size(); ++i) {
1091         OpenSubdiv::Osd::PatchArray const & patch = patches[i];
1092         OpenSubdiv::Far::PatchDescriptor desc = patch.GetDescriptor();
1093         OpenSubdiv::Far::PatchDescriptor::Type patchType = desc.GetType();
1094 
1095         D3D11_PRIMITIVE_TOPOLOGY topology;
1096 
1097         switch (patchType) {
1098         case OpenSubdiv::Far::PatchDescriptor::TRIANGLES:
1099             topology = D3D11_PRIMITIVE_TOPOLOGY_TRIANGLELIST;
1100             break;
1101         case OpenSubdiv::Far::PatchDescriptor::QUADS:
1102             topology = D3D11_PRIMITIVE_TOPOLOGY_LINELIST_ADJ;
1103             break;
1104         default:
1105             switch (desc.GetNumControlVertices()) {
1106             case 4:
1107                 topology = D3D11_PRIMITIVE_TOPOLOGY_4_CONTROL_POINT_PATCHLIST;
1108                 break;
1109             case 9:
1110                 topology = D3D11_PRIMITIVE_TOPOLOGY_9_CONTROL_POINT_PATCHLIST;
1111                 break;
1112             case 12:
1113                 topology = D3D11_PRIMITIVE_TOPOLOGY_12_CONTROL_POINT_PATCHLIST;
1114                 break;
1115             case 16:
1116                 topology = D3D11_PRIMITIVE_TOPOLOGY_16_CONTROL_POINT_PATCHLIST;
1117                 break;
1118             case 20:
1119                 topology = D3D11_PRIMITIVE_TOPOLOGY_20_CONTROL_POINT_PATCHLIST;
1120                 break;
1121             default:
1122                 assert(false);
1123                 break;
1124             }
1125             break;
1126         }
1127 
1128         Effect effect;
1129         effect.value = 0;
1130 
1131         effect.color = g_color;
1132         effect.displacement = g_displacement;
1133 
1134         effect.occlusion = g_occlusion;
1135         effect.normal = g_normal;
1136         effect.specular = g_specular;
1137         effect.patchCull = g_patchCull;
1138         effect.screenSpaceTess = g_screenSpaceTess;
1139         effect.fractionalSpacing = g_fractionalSpacing;
1140         effect.ibl = g_ibl;
1141         effect.wire = g_wire;
1142         effect.seamless = g_seamless;
1143 
1144         bindProgram(effect, patch);
1145 
1146         g_pd3dDeviceContext->IASetPrimitiveTopology(topology);
1147 
1148         g_pd3dDeviceContext->DrawIndexed(
1149             patch.GetNumPatches() * desc.GetNumControlVertices(),
1150             patch.GetIndexBase(), 0);
1151 
1152     }
1153 }
1154 
1155 //------------------------------------------------------------------------------
1156 static void
display()1157 display() {
1158 
1159     Stopwatch s;
1160     s.Start();
1161 
1162     float color[4] = {0.006f, 0.006f, 0.006f, 1.0f};
1163     g_pd3dDeviceContext->ClearRenderTargetView(g_pSwapChainRTV, color);
1164 
1165     // Clear the depth buffer.
1166     g_pd3dDeviceContext->ClearDepthStencilView(g_pDepthStencilView, D3D11_CLEAR_DEPTH, 1.0f, 0);
1167 
1168     if (g_ibl && g_sky) {
1169 
1170         float modelView[16], projection[16], mvp[16];
1171         double aspect = g_width/(double)g_height;
1172 
1173         identity(modelView);
1174         rotate(modelView, g_rotate[1], 1, 0, 0);
1175         rotate(modelView, g_rotate[0], 0, 1, 0);
1176         perspective(projection, 45.0f, (float)aspect, g_size*0.001f, g_size+g_dolly);
1177         multMatrix(mvp, modelView, projection);
1178 
1179         g_sky->Draw(g_pd3dDeviceContext, mvp);
1180     }
1181 
1182 // this query can be slow : comment out #define to turn off
1183 #define PIPELINE_STATISTICS
1184 #ifdef PIPELINE_STATISTICS
1185     g_pd3dDeviceContext->Begin(g_pipelineStatsQuery);
1186 #endif // PIPELINE_STATISTICS
1187 
1188     g_pd3dDeviceContext->OMSetDepthStencilState(g_pDepthStencilState, 1);
1189     g_pd3dDeviceContext->RSSetState(g_pRasterizerState);
1190 
1191     drawModel();
1192 
1193 #ifdef PIPELINE_STATISTICS
1194     g_pd3dDeviceContext->End(g_pipelineStatsQuery);
1195 #endif // PIPELINE_STATISTICS
1196 
1197     s.Stop();
1198     float drawCpuTime = float(s.GetElapsed() * 1000.0f);
1199 
1200     int timeElapsed = 0;
1201     // XXXX TODO GPU cycles elapsed query
1202     float drawGpuTime = timeElapsed / 1000.0f / 1000.0f;
1203 
1204     UINT64 numPrimsGenerated = 0;
1205 #ifdef PIPELINE_STATISTICS
1206     D3D11_QUERY_DATA_PIPELINE_STATISTICS pipelineStats;
1207     ZeroMemory(&pipelineStats, sizeof(pipelineStats));
1208     while (S_OK != g_pd3dDeviceContext->GetData(g_pipelineStatsQuery, &pipelineStats, g_pipelineStatsQuery->GetDataSize(), 0));
1209     numPrimsGenerated = pipelineStats.GSPrimitives;
1210 #endif // PIPELINE_STATISTICS
1211 
1212         g_fpsTimer.Stop();
1213     float elapsed = (float)g_fpsTimer.GetElapsed();
1214     if (!g_freeze)
1215         g_animTime += elapsed;
1216         g_fpsTimer.Start();
1217 
1218 
1219     if (g_hud->IsVisible()) {
1220 
1221         double fps = 1.0/elapsed;
1222 
1223         // Avereage fps over a defined number of time samples for
1224         // easier reading in the HUD
1225         g_fpsTimeSamples[g_currentFpsTimeSample++] = float(fps);
1226         if (g_currentFpsTimeSample >= NUM_FPS_TIME_SAMPLES)
1227             g_currentFpsTimeSample = 0;
1228         double averageFps = 0;
1229         for (int i = 0; i < NUM_FPS_TIME_SAMPLES; ++i) {
1230             averageFps += g_fpsTimeSamples[i]/(float)NUM_FPS_TIME_SAMPLES;
1231         }
1232 
1233         g_hud->DrawString(10, -220, "Ptex memory use : %.1f mb", g_ptexMemoryUsage/1024.0/1024.0);
1234         g_hud->DrawString(10, -180, "Tess level (+/-): %d", g_tessLevel);
1235 #ifdef PIPELINE_STATISTICS
1236         if (numPrimsGenerated > 1000000) {
1237             g_hud->DrawString(10, -160, "Primitives      : %3.1f million",
1238                              (float)numPrimsGenerated/1000000.0);
1239         } else if (numPrimsGenerated > 1000) {
1240             g_hud->DrawString(10, -160, "Primitives      : %3.1f thousand",
1241                              (float)numPrimsGenerated/1000.0);
1242         } else {
1243             g_hud->DrawString(10, -160, "Primitives      : %d", numPrimsGenerated);
1244         }
1245 #endif // PIPELINE_STATISTICS
1246         g_hud->DrawString(10, -140, "Vertices        : %d", g_mesh->GetNumVertices());
1247         g_hud->DrawString(10, -120, "Scheme          : %s", g_scheme == 0 ? "CATMARK" : "LOOP");
1248         g_hud->DrawString(10, -100, "GPU Kernel      : %.3f ms", g_gpuTime);
1249         g_hud->DrawString(10, -80,  "CPU Kernel      : %.3f ms", g_cpuTime);
1250         g_hud->DrawString(10, -60,  "GPU Draw        : %.3f ms", drawGpuTime);
1251         g_hud->DrawString(10, -40,  "CPU Draw        : %.3f ms", drawCpuTime);
1252         g_hud->DrawString(10, -20,  "FPS             : %3.1f", fps);
1253     }
1254 
1255     g_hud->Flush();
1256 
1257     g_pSwapChain->Present(0, 0);
1258 }
1259 
1260 //------------------------------------------------------------------------------
1261 static void
mouse(int button,int state,int x,int y)1262 mouse(int button, int state, int x, int y) {
1263 
1264     if (state == 0)
1265         g_hud->MouseRelease();
1266 
1267     if (button == 0 && state == 1 && g_hud->MouseClick(x, y)) return;
1268 
1269     if (button < 3) {
1270         g_prev_x = float(x);
1271         g_prev_y = float(y);
1272         g_mbutton[button] = state;
1273     }
1274 }
1275 
1276 //------------------------------------------------------------------------------
1277 static void
motion(int x,int y)1278 motion(int x, int y) {
1279 
1280     if (g_hud->MouseCapture()) {
1281         // check gui
1282         g_hud->MouseMotion(x, y);
1283     } else if (g_mbutton[0] && !g_mbutton[1] && !g_mbutton[2]) {
1284         // orbit
1285         g_rotate[0] += x - g_prev_x;
1286         g_rotate[1] += y - g_prev_y;
1287     } else if (!g_mbutton[0] && g_mbutton[1] && !g_mbutton[2]) {
1288         // pan
1289         g_pan[0] -= g_dolly*(x - g_prev_x)/g_width;
1290         g_pan[1] += g_dolly*(y - g_prev_y)/g_height;
1291     } else if ((g_mbutton[0] && g_mbutton[1] && !g_mbutton[2]) ||
1292                (!g_mbutton[0] && !g_mbutton[1] && g_mbutton[2])) {
1293         // dolly
1294         g_dolly -= g_dolly*0.01f*(x - g_prev_x);
1295         if(g_dolly <= 0.01) g_dolly = 0.01f;
1296     }
1297 
1298     g_prev_x = float(x);
1299     g_prev_y = float(y);
1300 }
1301 
1302 //-----------------------------------------------------------------------------
1303 static void
quit()1304 quit() {
1305 
1306     g_bDone = true;
1307 
1308     if (g_osdPTexImage) delete g_osdPTexImage;
1309     if (g_osdPTexDisplacement) delete g_osdPTexDisplacement;
1310     if (g_osdPTexOcclusion) delete g_osdPTexOcclusion;
1311     if (g_osdPTexSpecular) delete g_osdPTexSpecular;
1312 
1313     if (g_mesh) delete g_mesh;
1314     if (g_hud) delete g_hud;
1315 
1316     SAFE_RELEASE(g_pRasterizerState);
1317     SAFE_RELEASE(g_pInputLayout);
1318     SAFE_RELEASE(g_pDepthStencilState);
1319     SAFE_RELEASE(g_pcbPerFrame);
1320     SAFE_RELEASE(g_pcbTessellation);
1321     SAFE_RELEASE(g_pcbLighting);
1322     SAFE_RELEASE(g_pcbConfig);
1323     SAFE_RELEASE(g_pDepthStencilView);
1324 
1325     SAFE_RELEASE(g_pSwapChainRTV);
1326     SAFE_RELEASE(g_pSwapChain);
1327     SAFE_RELEASE(g_pd3dDeviceContext);
1328     SAFE_RELEASE(g_pd3dDevice);
1329 
1330     PostQuitMessage(0);
1331     exit(0);
1332 }
1333 
1334 //------------------------------------------------------------------------------
1335 static void
keyboard(char key)1336 keyboard(char key) {
1337 
1338     if (g_hud->KeyDown((int)tolower(key))) return;
1339 
1340     switch (key) {
1341         case 'Q': quit();
1342         case 'F': fitFrame(); break;
1343         case '+':
1344         case '=': g_tessLevel++; break;
1345         case '-': g_tessLevel = std::max(1, g_tessLevel-1); break;
1346         case 0x1b: g_hud->SetVisible(!g_hud->IsVisible()); break;
1347     }
1348 }
1349 
1350 //------------------------------------------------------------------------------
1351 static void
callbackWireframe(int b)1352 callbackWireframe(int b) {
1353     g_wire = b;
1354 }
1355 
1356 static void
callbackKernel(int k)1357 callbackKernel(int k) {
1358 
1359     g_kernel = k;
1360 
1361 #ifdef OPENSUBDIV_HAS_OPENCL
1362     if (g_kernel == kCL && (!g_clDeviceContext.IsInitialized())) {
1363         if (g_clDeviceContext.Initialize(g_pd3dDeviceContext) == false) {
1364             printf("Error in initializing OpenCL\n");
1365             exit(1);
1366         }
1367     }
1368 #endif
1369 #ifdef OPENSUBDIV_HAS_CUDA
1370     if (g_kernel == kCUDA && (!g_cudaDeviceContext.IsInitialized())) {
1371         if (g_cudaDeviceContext.Initialize(g_pd3dDevice) == false) {
1372             printf("Error in initializing Cuda\n");
1373             exit(1);
1374         }
1375     }
1376 #endif
1377 
1378     createOsdMesh(g_level, g_kernel);
1379 }
1380 
1381 static void
callbackScheme(int s)1382 callbackScheme(int s) {
1383     g_scheme = s;
1384     createOsdMesh(g_level, g_kernel);
1385 }
1386 static void
callbackLevel(int l)1387 callbackLevel(int l) {
1388     g_level = l;
1389     createOsdMesh(g_level, g_kernel);
1390 }
1391 static void
callbackColor(int c)1392 callbackColor(int c) {
1393     g_color = c;
1394 }
1395 static void
callbackDisplacement(int d)1396 callbackDisplacement(int d) {
1397     g_displacement = d;
1398 }
1399 static void
callbackNormal(int n)1400 callbackNormal(int n) {
1401     g_normal = n;
1402 }
1403 
1404 static void
callbackCheckBox(bool checked,int button)1405 callbackCheckBox(bool checked, int button) {
1406     bool rebuild = false;
1407 
1408     switch (button) {
1409     case HUD_CB_ADAPTIVE:
1410         g_adaptive = checked;
1411         rebuild = true;
1412         break;
1413     case HUD_CB_DISPLAY_OCCLUSION:
1414         g_occlusion = checked;
1415         break;
1416     case HUD_CB_DISPLAY_SPECULAR:
1417         g_specular = checked;
1418         break;
1419     case HUD_CB_ANIMATE_VERTICES:
1420         g_moveScale = checked ? 1.0f : 0.0f;
1421         g_animTime = 0;
1422         break;
1423     case HUD_CB_VIEW_LOD:
1424         g_screenSpaceTess = checked;
1425         break;
1426     case HUD_CB_FRACTIONAL_SPACING:
1427         g_fractionalSpacing = checked;
1428         break;
1429     case HUD_CB_PATCH_CULL:
1430         g_patchCull = checked;
1431         break;
1432     case HUD_CB_IBL:
1433         g_ibl = checked;
1434         break;
1435     case HUD_CB_SEAMLESS_MIPMAP:
1436         g_seamless = checked;
1437         break;
1438     case HUD_CB_FREEZE:
1439         g_freeze = checked;
1440         break;
1441     }
1442 
1443     if (rebuild)
1444         createOsdMesh(g_level, g_kernel);
1445 }
1446 
1447 static void
callbackSlider(float value,int data)1448 callbackSlider(float value, int data) {
1449     switch (data) {
1450     case 0:
1451         g_mipmapBias = value;
1452         break;
1453     case 1:
1454         g_displacementScale = value;
1455         break;
1456     }
1457 }
1458 
1459 static void
initHUD()1460 initHUD() {
1461     g_hud = new D3D11hud(g_pd3dDeviceContext);
1462     g_hud->Init(g_width, g_height);
1463 
1464 
1465     if (g_osdPTexOcclusion != NULL) {
1466         g_hud->AddCheckBox("Ambient Occlusion (A)", g_occlusion,
1467                           -200, 570, callbackCheckBox, HUD_CB_DISPLAY_OCCLUSION, 'a');
1468     }
1469     if (g_osdPTexSpecular != NULL)
1470         g_hud->AddCheckBox("Specular (S)", g_specular,
1471                           -200, 590, callbackCheckBox, HUD_CB_DISPLAY_SPECULAR, 's');
1472 
1473     if (g_diffuseEnvironmentMap || g_diffuseEnvironmentMap) {
1474         g_hud->AddCheckBox("IBL (I)", g_ibl,
1475                           -200, 610, callbackCheckBox, HUD_CB_IBL, 'i');
1476     }
1477 
1478     g_hud->AddCheckBox("Animate vertices (M)", g_moveScale != 0.0,
1479                       10, 30, callbackCheckBox, HUD_CB_ANIMATE_VERTICES, 'm');
1480     g_hud->AddCheckBox("Screen space LOD (V)",  g_screenSpaceTess,
1481                       10, 50, callbackCheckBox, HUD_CB_VIEW_LOD, 'v');
1482     g_hud->AddCheckBox("Fractional spacing (T)",  g_fractionalSpacing,
1483                       10, 70, callbackCheckBox, HUD_CB_FRACTIONAL_SPACING, 't');
1484     g_hud->AddCheckBox("Frustum Patch Culling (B)",  g_patchCull,
1485                       10, 90, callbackCheckBox, HUD_CB_PATCH_CULL, 'b');
1486     g_hud->AddCheckBox("Bloom (Y)", g_bloom,
1487                       10, 110, callbackCheckBox, HUD_CB_BLOOM, 'y');
1488     g_hud->AddCheckBox("Freeze (spc)", g_freeze,
1489                       10, 130, callbackCheckBox, HUD_CB_FREEZE, ' ');
1490 
1491     g_hud->AddRadioButton(HUD_RB_SCHEME, "CATMARK", true, 10, 190, callbackScheme, 0);
1492     g_hud->AddRadioButton(HUD_RB_SCHEME, "BILINEAR", false, 10, 210, callbackScheme, 1);
1493 
1494     g_hud->AddCheckBox("Adaptive (`)", g_adaptive,
1495                        10, 300, callbackCheckBox, HUD_CB_ADAPTIVE, '`');
1496 
1497     for (int i = 1; i < 8; ++i) {
1498         char level[16];
1499         sprintf(level, "Lv. %d", i);
1500         g_hud->AddRadioButton(HUD_RB_LEVEL, level, i == g_level,
1501                               10, 320+i*20, callbackLevel, i, '0'+i);
1502     }
1503 
1504     int compute_pulldown = g_hud->AddPullDown("Compute (K)", 475, 10, 300, callbackKernel, 'k');
1505     g_hud->AddPullDownButton(compute_pulldown, "CPU (K)", kCPU);
1506 #ifdef OPENSUBDIV_HAS_OPENMP
1507     g_hud->AddPullDownButton(compute_pulldown, "OPENMP", kOPENMP);
1508 #endif
1509 #ifdef OPENSUBDIV_HAS_TBB
1510     g_hud->AddPullDownButton(compute_pulldown, "TBB", kTBB);
1511 #endif
1512 #ifdef OPENSUBDIV_HAS_CUDA
1513     g_hud->AddPullDownButton(compute_pulldown, "CUDA", kCUDA);
1514 #endif
1515 #ifdef OPENSUBDIV_HAS_OPENCL
1516     if (CLDeviceContext::HAS_CL_VERSION_1_1()) {
1517         g_hud->AddPullDownButton(compute_pulldown, "OPENCL", kCL);
1518     }
1519 #endif
1520     g_hud->AddPullDownButton(compute_pulldown, "DirectCompute", kDirectCompute);
1521 
1522     int shading_pulldown = g_hud->AddPullDown("Shading (W)", 250, 10, 250, callbackWireframe, 'w');
1523     g_hud->AddPullDownButton(shading_pulldown, "Wire", DISPLAY_WIRE, g_wire==DISPLAY_WIRE);
1524     g_hud->AddPullDownButton(shading_pulldown, "Shaded", DISPLAY_SHADED, g_wire==DISPLAY_SHADED);
1525     g_hud->AddPullDownButton(shading_pulldown, "Wire+Shaded", DISPLAY_WIRE_ON_SHADED, g_wire==DISPLAY_WIRE_ON_SHADED);
1526 
1527     g_hud->AddLabel("Color (C)", -200, 10);
1528     g_hud->AddRadioButton(HUD_RB_COLOR, "None", (g_color == COLOR_NONE),
1529                          -200, 30, callbackColor, COLOR_NONE, 'c');
1530     g_hud->AddRadioButton(HUD_RB_COLOR, "Ptex Nearest", (g_color == COLOR_PTEX_NEAREST),
1531                          -200, 50, callbackColor, COLOR_PTEX_NEAREST, 'c');
1532     // Commented out : we need to add a texture sampler state to make this work
1533     //g_hud->AddRadioButton(HUD_RB_COLOR, "Ptex HW bilinear", (g_color == COLOR_PTEX_HW_BILINEAR),
1534     //                     -200, 70, callbackColor, COLOR_PTEX_HW_BILINEAR, 'c');
1535     g_hud->AddRadioButton(HUD_RB_COLOR, "Ptex bilinear", (g_color == COLOR_PTEX_BILINEAR),
1536                          -200, 90, callbackColor, COLOR_PTEX_BILINEAR, 'c');
1537     g_hud->AddRadioButton(HUD_RB_COLOR, "Ptex biquadratic", (g_color == COLOR_PTEX_BIQUADRATIC),
1538                          -200, 110, callbackColor, COLOR_PTEX_BIQUADRATIC, 'c');
1539     g_hud->AddRadioButton(HUD_RB_COLOR, "Patch type", (g_color == COLOR_PATCHTYPE),
1540                          -200, 130, callbackColor, COLOR_PATCHTYPE, 'c');
1541     g_hud->AddRadioButton(HUD_RB_COLOR, "Patch coord", (g_color == COLOR_PATCHCOORD),
1542                          -200, 150, callbackColor, COLOR_PATCHCOORD, 'c');
1543     g_hud->AddRadioButton(HUD_RB_COLOR, "Normal", (g_color == COLOR_NORMAL),
1544                          -200, 170, callbackColor, COLOR_NORMAL, 'c');
1545 
1546     if (g_osdPTexDisplacement != NULL) {
1547         g_hud->AddLabel("Displacement (D)", -200, 200);
1548         g_hud->AddRadioButton(HUD_RB_DISPLACEMENT, "None",
1549                              (g_displacement == DISPLACEMENT_NONE),
1550                              -200, 220, callbackDisplacement, DISPLACEMENT_NONE, 'd');
1551         // Commented out : we need to add a texture sampler state to make this work
1552         //g_hud->AddRadioButton(HUD_RB_DISPLACEMENT, "HW bilinear",
1553         //                     (g_displacement == DISPLACEMENT_HW_BILINEAR),
1554         //                     -200, 240, callbackDisplacement, DISPLACEMENT_HW_BILINEAR, 'd');
1555         g_hud->AddRadioButton(HUD_RB_DISPLACEMENT, "Bilinear",
1556                              (g_displacement == DISPLACEMENT_BILINEAR),
1557                              -200, 260, callbackDisplacement, DISPLACEMENT_BILINEAR, 'd');
1558         g_hud->AddRadioButton(HUD_RB_DISPLACEMENT, "Biquadratic",
1559                              (g_displacement == DISPLACEMENT_BIQUADRATIC),
1560                              -200, 280, callbackDisplacement, DISPLACEMENT_BIQUADRATIC, 'd');
1561 
1562         g_hud->AddLabel("Normal (N)", -200, 310);
1563         g_hud->AddRadioButton(HUD_RB_NORMAL, "Surface",
1564                              (g_normal == NORMAL_SURFACE),
1565                              -200, 330, callbackNormal, NORMAL_SURFACE, 'n');
1566         g_hud->AddRadioButton(HUD_RB_NORMAL, "Facet",
1567                              (g_normal == NORMAL_FACET),
1568                              -200, 350, callbackNormal, NORMAL_FACET, 'n');
1569         g_hud->AddRadioButton(HUD_RB_NORMAL, "HW Screen space",
1570                              (g_normal == NORMAL_HW_SCREENSPACE),
1571                              -200, 370, callbackNormal, NORMAL_HW_SCREENSPACE, 'n');
1572         g_hud->AddRadioButton(HUD_RB_NORMAL, "Screen space",
1573                              (g_normal == NORMAL_SCREENSPACE),
1574                              -200, 390, callbackNormal, NORMAL_SCREENSPACE, 'n');
1575         g_hud->AddRadioButton(HUD_RB_NORMAL, "Biquadratic",
1576                              (g_normal == NORMAL_BIQUADRATIC),
1577                              -200, 410, callbackNormal, NORMAL_BIQUADRATIC, 'n');
1578         g_hud->AddRadioButton(HUD_RB_NORMAL, "Biquadratic WG",
1579                              (g_normal == NORMAL_BIQUADRATIC_WG),
1580                              -200, 430, callbackNormal, NORMAL_BIQUADRATIC_WG, 'n');
1581     }
1582 
1583     g_hud->AddSlider("Mipmap Bias", 0, 5, 0,
1584                     -200, 450, 20, false, callbackSlider, 0);
1585     g_hud->AddSlider("Displacement", 0, 5, 1,
1586                     -200, 490, 20, false, callbackSlider, 1);
1587     g_hud->AddCheckBox("Seamless Mipmap", g_seamless,
1588                        -200, 530, callbackCheckBox, HUD_CB_SEAMLESS_MIPMAP, 'j');
1589 
1590 }
1591 
1592 //------------------------------------------------------------------------------
1593 static bool
initD3D11(HWND hWnd)1594 initD3D11(HWND hWnd) {
1595 
1596     D3D_DRIVER_TYPE driverTypes[] = {
1597         D3D_DRIVER_TYPE_HARDWARE,
1598         D3D_DRIVER_TYPE_WARP,
1599         D3D_DRIVER_TYPE_REFERENCE,
1600     };
1601 
1602     UINT numDriverTypes = ARRAYSIZE(driverTypes);
1603 
1604     int width = g_width,
1605         height = g_height;
1606     if (g_fullscreen) {
1607         HWND const desktop = GetDesktopWindow();
1608         RECT rect;
1609         GetWindowRect(desktop, &rect);
1610         width = (int)rect.right;
1611         height = (int)rect.bottom;
1612     }
1613     DXGI_SWAP_CHAIN_DESC hDXGISwapChainDesc;
1614     hDXGISwapChainDesc.BufferDesc.Width = width;
1615     hDXGISwapChainDesc.BufferDesc.Height = height;
1616     hDXGISwapChainDesc.BufferDesc.RefreshRate.Numerator  = 0;
1617     hDXGISwapChainDesc.BufferDesc.RefreshRate.Denominator = 1;
1618     hDXGISwapChainDesc.BufferDesc.Format = DXGI_FORMAT_R8G8B8A8_UNORM_SRGB;
1619     hDXGISwapChainDesc.BufferDesc.ScanlineOrdering = DXGI_MODE_SCANLINE_ORDER_UNSPECIFIED;
1620     hDXGISwapChainDesc.BufferDesc.Scaling = DXGI_MODE_SCALING_UNSPECIFIED;
1621     hDXGISwapChainDesc.SampleDesc.Count = 1;
1622     hDXGISwapChainDesc.SampleDesc.Quality = 0;
1623     hDXGISwapChainDesc.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT;
1624     hDXGISwapChainDesc.BufferCount = 1;
1625     hDXGISwapChainDesc.OutputWindow = hWnd;
1626     hDXGISwapChainDesc.Windowed = !g_fullscreen;
1627     hDXGISwapChainDesc.SwapEffect = DXGI_SWAP_EFFECT_DISCARD;
1628     hDXGISwapChainDesc.Flags = DXGI_SWAP_CHAIN_FLAG_ALLOW_MODE_SWITCH;
1629 
1630     // create device and swap chain
1631     HRESULT hr;
1632     D3D_DRIVER_TYPE hDriverType = D3D_DRIVER_TYPE_NULL;
1633     D3D_FEATURE_LEVEL hFeatureLevel = D3D_FEATURE_LEVEL_11_0;
1634     for(UINT driverTypeIndex=0; driverTypeIndex < numDriverTypes; driverTypeIndex++){
1635         hDriverType = driverTypes[driverTypeIndex];
1636         unsigned int deviceFlags = 0;
1637 #ifndef NDEBUG
1638                 // XXX: this is problematic in some environments.
1639 //                deviceFlags |= D3D11_CREATE_DEVICE_DEBUG;
1640 #endif
1641         hr = D3D11CreateDeviceAndSwapChain(NULL,
1642                                            hDriverType, NULL, deviceFlags, NULL, 0,
1643                                            D3D11_SDK_VERSION, &hDXGISwapChainDesc,
1644                                            &g_pSwapChain, &g_pd3dDevice,
1645                                            &hFeatureLevel, &g_pd3dDeviceContext);
1646         if(SUCCEEDED(hr)){
1647             break;
1648         }
1649     }
1650 
1651     if(FAILED(hr)){
1652         MessageBoxW(hWnd, L"D3D11CreateDeviceAndSwapChain", L"Err", MB_ICONSTOP);
1653         return false;
1654     }
1655 
1656 #ifndef NDEBUG
1657     // set break points on directx errors
1658     ID3D11Debug *d3dDebug = nullptr;
1659     hr = g_pd3dDevice->QueryInterface(__uuidof(ID3D11Debug), (void**)&d3dDebug);
1660     if (SUCCEEDED(hr)) {
1661         ID3D11InfoQueue *d3dInfoQueue = nullptr;
1662         hr = d3dDebug->QueryInterface(__uuidof(ID3D11InfoQueue), (void**)&d3dInfoQueue);
1663         if (SUCCEEDED(hr)) {
1664 
1665             d3dInfoQueue->SetBreakOnSeverity(D3D11_MESSAGE_SEVERITY_CORRUPTION, true);
1666             d3dInfoQueue->SetBreakOnSeverity(D3D11_MESSAGE_SEVERITY_ERROR, true);
1667             d3dInfoQueue->SetBreakOnSeverity(D3D11_MESSAGE_SEVERITY_WARNING, true);
1668 
1669             D3D11_MESSAGE_ID denied[] = { D3D11_MESSAGE_ID_SETPRIVATEDATA_CHANGINGPARAMS };
1670             D3D11_INFO_QUEUE_FILTER filter;
1671             memset(&filter, 0, sizeof(filter));
1672             filter.DenyList.NumIDs = _countof(denied);
1673             filter.DenyList.pIDList = denied;
1674             d3dInfoQueue->AddStorageFilterEntries(&filter);
1675 
1676             d3dInfoQueue->Release();
1677         }
1678         d3dDebug->Release();
1679     }
1680 #endif
1681 
1682     // create rasterizer
1683     D3D11_RASTERIZER_DESC rasterDesc;
1684     ZeroMemory(&rasterDesc, sizeof(rasterDesc));
1685     rasterDesc.AntialiasedLineEnable = false;
1686     rasterDesc.CullMode = D3D11_CULL_BACK;
1687     rasterDesc.DepthBias = 0;
1688     rasterDesc.DepthBiasClamp = 0.0f;
1689     rasterDesc.DepthClipEnable = true;
1690     rasterDesc.FillMode = D3D11_FILL_SOLID;
1691     rasterDesc.FrontCounterClockwise = true;
1692     rasterDesc.MultisampleEnable = false;
1693     rasterDesc.ScissorEnable = false;
1694     rasterDesc.SlopeScaledDepthBias = 0.0f;
1695 
1696     g_pd3dDevice->CreateRasterizerState(&rasterDesc, &g_pRasterizerState);
1697     assert(g_pRasterizerState);
1698 
1699     __declspec(align(16))
1700     struct Lighting {
1701         struct Light {
1702             float position[4];
1703             float ambient[4];
1704             float diffuse[4];
1705             float specular[4];
1706         } lightSource[2];
1707     } lightingData = {
1708         0.5, 0.2f, 1.0f, 0.0f,
1709         0.1f, 0.1f, 0.1f, 1.0f,
1710         0.7f, 0.7f, 0.7f, 1.0f,
1711         0.8f, 0.8f, 0.8f, 1.0f,
1712 
1713         -0.8f, 0.4f, -1.0f, 0.0f,
1714         0.0f, 0.0f, 0.0f, 1.0f,
1715         0.5f, 0.5f, 0.5f, 1.0f,
1716         0.8f, 0.8f, 0.8f, 1.0f,
1717     };
1718 
1719     D3D11_BUFFER_DESC cbDesc;
1720     ZeroMemory(&cbDesc, sizeof(cbDesc));
1721     cbDesc.Usage = D3D11_USAGE_DYNAMIC;
1722     cbDesc.BindFlags = D3D11_BIND_CONSTANT_BUFFER;
1723     cbDesc.CPUAccessFlags = D3D11_CPU_ACCESS_WRITE;
1724     cbDesc.MiscFlags = 0;
1725     cbDesc.ByteWidth = sizeof(lightingData);
1726     D3D11_SUBRESOURCE_DATA initData;
1727     initData.pSysMem = &lightingData;
1728     g_pd3dDevice->CreateBuffer(&cbDesc, &initData, &g_pcbLighting);
1729     assert(g_pcbLighting);
1730 
1731     // create depth stencil state
1732     D3D11_DEPTH_STENCIL_DESC depthStencilDesc;
1733     ZeroMemory(&depthStencilDesc, sizeof(depthStencilDesc));
1734     depthStencilDesc.DepthEnable = true;
1735     depthStencilDesc.DepthWriteMask = D3D11_DEPTH_WRITE_MASK_ALL;
1736     depthStencilDesc.DepthFunc = D3D11_COMPARISON_LESS_EQUAL;
1737     depthStencilDesc.StencilEnable = false;
1738 
1739     g_pd3dDevice->CreateDepthStencilState(&depthStencilDesc, &g_pDepthStencilState);
1740     assert(g_pDepthStencilState);
1741 
1742 #ifdef PIPELINE_STATISTICS
1743     // Create pipeline statistics query
1744     D3D11_QUERY_DESC queryDesc;
1745     ZeroMemory(&queryDesc, sizeof(D3D11_QUERY_DESC));
1746     queryDesc.Query = D3D11_QUERY_PIPELINE_STATISTICS;
1747     g_pd3dDevice->CreateQuery(&queryDesc, &g_pipelineStatsQuery);
1748 #endif // PIPELINE_STATISTICS
1749 
1750     return true;
1751 }
1752 
1753 static bool
updateRenderTarget(HWND hWnd)1754 updateRenderTarget(HWND hWnd) {
1755 
1756     RECT rc;
1757     GetClientRect(hWnd, &rc);
1758     UINT width = rc.right - rc.left;
1759     UINT height = rc.bottom - rc.top;
1760 
1761     if (g_pSwapChainRTV && (g_width == width) && (g_height == height)) {
1762         return true;
1763     }
1764     g_width = width;
1765     g_height = height;
1766 
1767     g_hud->Rebuild(g_width, g_height);
1768 
1769     SAFE_RELEASE(g_pSwapChainRTV);
1770 
1771     g_pSwapChain->ResizeBuffers(0, g_width, g_height, DXGI_FORMAT_UNKNOWN, 0);
1772 
1773     // get backbuffer of swap chain
1774     ID3D11Texture2D* hpBackBuffer = NULL;
1775     if(FAILED(g_pSwapChain->GetBuffer(0, __uuidof(ID3D11Texture2D), (void**)&hpBackBuffer))){
1776         MessageBoxW(hWnd, L"SwpChain GetBuffer", L"Err", MB_ICONSTOP);
1777         return false;
1778     }
1779 
1780     // create render target from the back buffer
1781     if(FAILED(g_pd3dDevice->CreateRenderTargetView(hpBackBuffer, NULL, &g_pSwapChainRTV))){
1782         MessageBoxW(hWnd, L"CreateRenderTargetView", L"Err", MB_ICONSTOP);
1783         return false;
1784     }
1785     SAFE_RELEASE(hpBackBuffer);
1786 
1787     // create depth buffer
1788     D3D11_TEXTURE2D_DESC depthBufferDesc;
1789     ZeroMemory(&depthBufferDesc, sizeof(depthBufferDesc));
1790     depthBufferDesc.Width = g_width;
1791     depthBufferDesc.Height = g_height;
1792     depthBufferDesc.MipLevels = 1;
1793     depthBufferDesc.ArraySize = 1;
1794     depthBufferDesc.Format = DXGI_FORMAT_D24_UNORM_S8_UINT;
1795     depthBufferDesc.SampleDesc.Count = 1;
1796     depthBufferDesc.SampleDesc.Quality = 0;
1797     depthBufferDesc.Usage = D3D11_USAGE_DEFAULT;
1798     depthBufferDesc.BindFlags = D3D11_BIND_DEPTH_STENCIL;
1799     depthBufferDesc.CPUAccessFlags = 0;
1800     depthBufferDesc.MiscFlags = 0;
1801 
1802     g_pd3dDevice->CreateTexture2D(&depthBufferDesc, NULL, &g_pDepthStencilBuffer);
1803     assert(g_pDepthStencilBuffer);
1804 
1805     D3D11_DEPTH_STENCIL_VIEW_DESC depthStencilViewDesc;
1806     ZeroMemory(&depthStencilViewDesc, sizeof(depthStencilViewDesc));
1807     depthStencilViewDesc.Format = DXGI_FORMAT_D24_UNORM_S8_UINT;
1808     depthStencilViewDesc.ViewDimension = D3D11_DSV_DIMENSION_TEXTURE2D;
1809     depthStencilViewDesc.Texture2D.MipSlice = 0;
1810 
1811     g_pd3dDevice->CreateDepthStencilView(g_pDepthStencilBuffer, &depthStencilViewDesc, &g_pDepthStencilView);
1812     assert(g_pDepthStencilView);
1813 
1814     // set device context to the render target
1815     g_pd3dDeviceContext->OMSetRenderTargets(1, &g_pSwapChainRTV, g_pDepthStencilView);
1816 
1817     // init viewport
1818     D3D11_VIEWPORT vp;
1819     vp.TopLeftX = 0;
1820     vp.TopLeftY = 0;
1821     vp.Width = (float)g_width;
1822     vp.Height = (float)g_height;
1823     vp.MinDepth = 0.0f;
1824     vp.MaxDepth = 1.0f;
1825     g_pd3dDeviceContext->RSSetViewports(1, &vp);
1826 
1827     return true;
1828 }
1829 
1830 //------------------------------------------------------------------------------
1831 static void
callbackError(OpenSubdiv::Far::ErrorType err,const char * message)1832 callbackError(OpenSubdiv::Far::ErrorType err, const char *message) {
1833     std::ostringstream s;
1834     s << "Error: " << err << "\n";
1835     s << message;
1836     OutputDebugString(s.str().c_str());
1837 }
1838 
1839 //------------------------------------------------------------------------------
1840 static LRESULT WINAPI
msgProc(HWND hWnd,UINT msg,WPARAM wParam,LPARAM lParam)1841 msgProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam) {
1842 
1843     switch(msg)
1844     {
1845         case WM_KEYDOWN:
1846             keyboard(MapVirtualKey(UINT(wParam), MAPVK_VK_TO_CHAR));
1847             break;
1848         case WM_DESTROY:
1849             quit();
1850             return 0;
1851         case WM_MOUSEMOVE:
1852             motion(LOWORD(lParam), HIWORD(lParam));
1853             return 0;
1854         case WM_LBUTTONDOWN:
1855             mouse(0, 1, LOWORD(lParam), HIWORD(lParam));
1856             return 0;
1857         case WM_LBUTTONUP:
1858             mouse(0, 0, LOWORD(lParam), HIWORD(lParam));
1859             return 0;
1860         case WM_MBUTTONDOWN:
1861             mouse(1, 1, LOWORD(lParam), HIWORD(lParam));
1862             return 0;
1863         case WM_MBUTTONUP:
1864             mouse(1, 0, LOWORD(lParam), HIWORD(lParam));
1865             return 0;
1866         case WM_RBUTTONDOWN:
1867             mouse(2, 1, LOWORD(lParam), HIWORD(lParam));
1868             return 0;
1869         case WM_RBUTTONUP:
1870             mouse(2, 0, LOWORD(lParam), HIWORD(lParam));
1871             return 0;
1872         case WM_PAINT:
1873             ValidateRect(hWnd, NULL);
1874             return 0;
1875     }
1876     return DefWindowProc(hWnd, msg, wParam, lParam);
1877 }
1878 
1879 static std::vector<std::string>
tokenize(std::string const & src)1880 tokenize(std::string const & src) {
1881 
1882     std::vector<std::string> result;
1883 
1884     std::stringstream input(src);
1885     std::copy(std::istream_iterator<std::string>(input),
1886               std::istream_iterator<std::string>(),
1887               std::back_inserter< std::vector<std::string> >(result));
1888 
1889     return result;
1890 }
1891 
1892 //------------------------------------------------------------------------------
usage(const char * program)1893 void usage(const char *program) {
1894     printf("Usage: %s [options] <color.ptx> [<displacement.ptx>] [occlusion.ptx>] "
1895            "[specular.ptx] [pose.obj]...\n", program);
1896     printf("Options:  -l level                : subdivision level\n");
1897     printf("          -c count                : frame count until exit (for profiler)\n");
1898     printf("          -d <diffseEnvMap.hdr>   : diffuse environment map for IBL\n");
1899     printf("          -e <specularEnvMap.hdr> : specular environment map for IBL\n");
1900     printf("          -yup                    : Y-up model\n");
1901     printf("          -m level                : max mimmap level (default=10)\n");
1902     printf("          -x <ptex limit MB>      : ptex target memory size\n");
1903     printf("          --disp <scale>          : Displacment scale\n");
1904 }
1905 
1906 //------------------------------------------------------------------------------
1907 
1908 int WINAPI
WinMain(HINSTANCE hInstance,HINSTANCE hPrevInstance,LPTSTR lpCmdLine,int nCmdShow)1909 WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPTSTR lpCmdLine, int nCmdShow) {
1910 
1911     // register window class
1912     TCHAR szWindowClass[] = "OPENSUBDIV_EXAMPLE";
1913     WNDCLASS wcex;
1914     wcex.style          = CS_HREDRAW | CS_VREDRAW;
1915     wcex.lpfnWndProc    = msgProc;
1916     wcex.cbClsExtra     = 0;
1917     wcex.cbWndExtra     = 0;
1918     wcex.hInstance      = hInstance;
1919     wcex.hIcon          = NULL;
1920     wcex.hCursor        = LoadCursor(NULL, IDC_ARROW);
1921     wcex.hbrBackground  = (HBRUSH)(COLOR_WINDOW+1);
1922     wcex.lpszMenuName   = NULL;
1923     wcex.lpszClassName  = szWindowClass;
1924     RegisterClass(&wcex);
1925 
1926     // create window
1927     RECT rect = { 0, 0, g_width, g_height };
1928     AdjustWindowRect(&rect, WS_OVERLAPPEDWINDOW, FALSE);
1929 
1930     static const char windowTitle[] = "OpenSubdiv dxPtexViewer " OPENSUBDIV_VERSION_STRING;
1931 
1932     HWND hWnd = CreateWindow(szWindowClass,
1933                         windowTitle,
1934                         WS_OVERLAPPEDWINDOW | WS_VISIBLE,
1935                         CW_USEDEFAULT,
1936                         CW_USEDEFAULT,
1937                         rect.right - rect.left,
1938                         rect.bottom - rect.top,
1939                         NULL,
1940                         NULL,
1941                         hInstance,
1942                         NULL);
1943 
1944     const char *diffuseEnvironmentMap = NULL, *specularEnvironmentMap = NULL;
1945     const char *colorFilename = NULL, *displacementFilename = NULL,
1946         *occlusionFilename = NULL, *specularFilename = NULL;
1947     int memLimit = 0;
1948 
1949     ArgOptions args;
1950     args.Parse(__argc, __argv);
1951 
1952     std::vector<const char *> animobjs = args.GetObjFiles();
1953     g_fullscreen = args.GetFullScreen();
1954 
1955     g_yup = args.GetYUp();
1956     g_adaptive = args.GetAdaptive();
1957     g_level = args.GetLevel();
1958     g_repeatCount = args.GetRepeatCount();
1959 
1960     const std::vector<const char *> &argvRem = args.GetRemainingArgs();
1961     for (size_t i = 0; i < argvRem.size(); ++i) {
1962         if (!strcmp(argvRem[i], "-d")) {
1963             diffuseEnvironmentMap = argvRem[++i];
1964         } else if (!strcmp(argvRem[i], "-e")) {
1965             specularEnvironmentMap = argvRem[++i];
1966         } else if (!strcmp(argvRem[i], "-m")) {
1967             g_maxMipmapLevels = atoi(argvRem[++i]);
1968         } else if (!strcmp(argvRem[i], "-x")) {
1969             memLimit = atoi(argvRem[++i]);
1970         } else if (!strcmp(argvRem[i], "--disp")) {
1971             g_displacementScale = (float)atof(argvRem[++i]);
1972         } else if (colorFilename == NULL) {
1973             colorFilename = argvRem[i];
1974         } else if (displacementFilename == NULL) {
1975             displacementFilename = argvRem[i];
1976             g_displacement = DISPLACEMENT_BILINEAR;
1977             g_normal = NORMAL_BIQUADRATIC;
1978         } else if (occlusionFilename == NULL) {
1979             occlusionFilename = argvRem[i];
1980             g_occlusion = 1;
1981         } else if (specularFilename == NULL) {
1982             specularFilename = argvRem[i];
1983             g_specular = 1;
1984         } else {
1985             args.PrintUnrecognizedArgWarning(argvRem[i]);
1986         }
1987     }
1988 
1989     OpenSubdiv::Far::SetErrorCallback(callbackError);
1990 
1991     g_ptexColorFilename = colorFilename;
1992     if (g_ptexColorFilename == NULL) {
1993         usage(__argv[0]);
1994         return 1;
1995     }
1996 
1997     initD3D11(hWnd);
1998 
1999     createOsdMesh(g_level, g_kernel);
2000 
2001     // load ptex files
2002     g_osdPTexImage = createPtex(colorFilename, memLimit);
2003     if (displacementFilename)
2004         g_osdPTexDisplacement = createPtex(displacementFilename, memLimit);
2005     if (occlusionFilename)
2006         g_osdPTexOcclusion = createPtex(occlusionFilename, memLimit);
2007     if (specularFilename)
2008         g_osdPTexSpecular = createPtex(specularFilename, memLimit);
2009 
2010     g_ptexMemoryUsage =
2011         (g_osdPTexImage ? g_osdPTexImage->GetMemoryUsage() : 0)
2012         + (g_osdPTexDisplacement ? g_osdPTexDisplacement->GetMemoryUsage() : 0)
2013         + (g_osdPTexOcclusion ? g_osdPTexOcclusion->GetMemoryUsage() : 0)
2014         + (g_osdPTexSpecular ? g_osdPTexSpecular->GetMemoryUsage() : 0);
2015 
2016     // load animation obj sequences (optional)
2017     if (!animobjs.empty()) {
2018         //  The Scheme passed here should ideally match the Ptex geometry
2019         //  (not the defaults from the command line), but only the vertex
2020         //  positions of the ObjAnim are used, so it is effectively ignored
2021         g_objAnim = ObjAnim::Create(animobjs, kCatmark);
2022         if (g_objAnim == 0) {
2023             printf("Error in reading animation Obj file sequence\n");
2024             goto end;
2025         }
2026 
2027         const Shape *animShape = g_objAnim->GetShape();
2028         if (animShape->verts.size() != g_positions.size()) {
2029             printf("Error in animation sequence, "
2030                    "does not match ptex vertex count\n");
2031             goto end;
2032         }
2033 
2034     }
2035 
2036     // IBL textures
2037     if (diffuseEnvironmentMap) {
2038 
2039         g_diffuseEnvironmentMap =
2040             createHDRTexture(g_pd3dDevice, diffuseEnvironmentMap);
2041         assert(g_diffuseEnvironmentMap);
2042 
2043         D3D11_SHADER_RESOURCE_VIEW_DESC srvDesc;
2044         ZeroMemory(&srvDesc, sizeof(srvDesc));
2045         srvDesc.Format = DXGI_FORMAT_R32G32B32A32_FLOAT;
2046         srvDesc.ViewDimension = D3D11_SRV_DIMENSION_TEXTURE2D;
2047         srvDesc.Texture2D.MostDetailedMip = 0;
2048         srvDesc.Texture2D.MipLevels = 1;
2049         g_pd3dDevice->CreateShaderResourceView(g_diffuseEnvironmentMap, &srvDesc, &g_diffuseEnvironmentSRV);
2050         assert(g_diffuseEnvironmentSRV);
2051     }
2052 
2053     if (specularEnvironmentMap) {
2054 
2055         g_specularEnvironmentMap =
2056             createHDRTexture(g_pd3dDevice, specularEnvironmentMap);
2057         assert(g_specularEnvironmentMap);
2058 
2059         D3D11_SHADER_RESOURCE_VIEW_DESC srvDesc;
2060         ZeroMemory(&srvDesc, sizeof(srvDesc));
2061         srvDesc.Format = DXGI_FORMAT_R32G32B32A32_FLOAT;
2062         srvDesc.ViewDimension = D3D11_SRV_DIMENSION_TEXTURE2D;
2063         srvDesc.Texture2D.MostDetailedMip = 0;
2064         srvDesc.Texture2D.MipLevels = 1;
2065         g_pd3dDevice->CreateShaderResourceView(g_specularEnvironmentMap, &srvDesc, &g_specularEnvironmentSRV);
2066         assert(g_specularEnvironmentSRV);
2067     }
2068 
2069     if (g_diffuseEnvironmentMap || g_specularEnvironmentMap) {
2070 
2071         // texture sampler
2072         D3D11_SAMPLER_DESC samplerDesc;
2073         ZeroMemory(&samplerDesc, sizeof(samplerDesc));
2074         samplerDesc.Filter = D3D11_FILTER_MIN_MAG_LINEAR_MIP_POINT;
2075         samplerDesc.AddressU = samplerDesc.AddressV = samplerDesc.AddressW = D3D11_TEXTURE_ADDRESS_WRAP;
2076         samplerDesc.MaxAnisotropy = 0;
2077         samplerDesc.ComparisonFunc = D3D11_COMPARISON_NEVER;
2078         samplerDesc.MinLOD = 0;
2079         samplerDesc.MaxLOD = D3D11_FLOAT32_MAX;
2080         samplerDesc.BorderColor[0] = samplerDesc.BorderColor[1] = samplerDesc.BorderColor[2] = samplerDesc.BorderColor[3] = 0.0f;
2081         g_pd3dDevice->CreateSamplerState(&samplerDesc, &g_iblSampler);
2082 
2083         g_sky = new Sky(g_pd3dDevice, g_specularEnvironmentMap!=0 ?
2084             g_specularEnvironmentMap : g_diffuseEnvironmentMap);
2085     }
2086 
2087     initHUD();
2088 
2089     fitFrame();
2090 
2091     // main loop
2092     while (g_bDone == false) {
2093         MSG msg;
2094         ZeroMemory(&msg, sizeof(msg));
2095         while (msg.message != WM_QUIT) {
2096             while (PeekMessage(&msg, NULL, 0U, 0U, PM_REMOVE)) {
2097                 if (msg.message == WM_QUIT) goto end;
2098                 TranslateMessage(&msg);
2099                 DispatchMessage(&msg);
2100             }
2101             if (!g_freeze)
2102                 g_frame++;
2103 
2104             updateGeom();
2105             updateRenderTarget(hWnd);
2106             display();
2107         }
2108     }
2109     end:
2110 
2111     quit();
2112     return 0;
2113 }
2114 
2115 //------------------------------------------------------------------------------
2116