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