· 6 years ago · Jan 21, 2020, 03:46 PM
1/*--------------------------------------------------------------------------------*
2 Copyright (C)Nintendo All rights reserved.
3
4 These coded instructions, statements, and computer programs contain proprietary
5 information of Nintendo and/or its licensed developers and are protected by
6 national and international copyright laws. They may not be disclosed to third
7 parties or copied or duplicated in any form, in whole or in part, without the
8 prior written consent of Nintendo.
9
10 The content herein is highly confidential and should be handled accordingly.
11 *--------------------------------------------------------------------------------*/
12
13
14 /**
15 * @examplesource{RenderToTexture.cpp,PageSampleNvnSimple04}
16 *
17 * @brief
18 * A class that shows a multi-pass rendering.
19 */
20
21 /**
22 * @page PageSampleNvnSimple04 Nvn Simple 04 : Render To Texture
23 * @tableofcontents
24 *
25 * @brief
26 * This sample renders a scene into an application-specific texture, which is then used to
27 * draw a secondary scene that is then displayed to screen. This sample introduces how to
28 * render to a texture and multi-pass rendering.
29 *
30 * @section PageSampleNvnSimple04_SectionBrief Overview
31 * This sample implements the rendering of a scene that utilizes two passes to
32 * introduces how to render to a texture and multi-pass rendering.
33 * One pass to render several shapes into an application-defined texture (i.e. a texture
34 * other than the display target texture used by GraphicsSystem), and then another pass
35 * to use that texture to render the final scene destined for display.
36 *
37 * @subsection PageSampleNvnSimple04_SectionExpectedOutput Expected Output
38 * @image html Applications\NvnSimple04RenderToTexture\NvnSimple04RenderToTexture.png
39 *
40 * @section PageSampleNvnSimple04_SectionFileStructure File Structure
41 * The sample's source file and Visual Studio solutions can be found at
42 * @link ../../../Samples/Sources/Applications/NvnSimple04RenderToTexture Samples/Sources/Applications/NvnSimple04RenderToTexture @endlink
43 *
44 * <table>
45 * <tr><td> @link RenderToTexture.h RenderToTexture.h@endlink, @link RenderToTexture.cpp RenderToTexture.cpp@endlink </td><td> @copybrief RenderToTexture.h </td></tr>
46 * <tr><td> @link Shape.h Shape.h@endlink, @link Shape.cpp Shape.cpp@endlink </td><td> @copybrief Shape.h </td></tr>
47 * <tr><td> NvnSimple04.vs </td><td> Dependent vetex shader which is used for rendering a texture to screen </td></tr>
48 * <tr><td> NvnSimple04.fs </td><td> Dependent fragment shader which is used for rendering a texture to screen </td></tr>
49 * </table>
50 *
51 * The dependent shader codes which are shared by samples can be found at
52 * Samples/Sources/Resources/NvnSimple/Shaders
53 *
54 * <table>
55 * <tr><td> SimplePrimitiveRenderer.vs </td><td> Dependent vetex shader which is used for rendering shapes to texture </td></tr>
56 * <tr><td> SimplePrimitiveRenderer.fs </td><td> Dependent fragment shader which is used for rendering shapes to texture </td></tr>
57 * </table>
58 *
59 * The tool NvnSimpleShaderCompiler, and library which contains common code shared by the NvnSimple samples can be found at
60 * @link ../../../Samples/Sources/Libraries/NvnSimple Samples/Sources/Libraries/NvnSimple @endlink
61 *
62 * @section PageSampleNvnSimple04_SectionNecessaryEnvironment System Requirements
63 * No extra system requirements.
64 *
65 * @section PageSampleNvnSimple04_SectionHowToOperate Operation Procedures
66 * Use Joy-Con、DebugPad、Keyboard when using PC to operate.
67 * <p>
68 * <table>
69 * <tr><th> Input </th><th> Operation </th></tr>
70 * <tr><td> A Button or A Key </td><td> Toggle command buffer reuse on/off </td></tr>
71 * <tr><td> B Button or B Key</td><td> Show/hide information </td></tr>
72 * </table>
73 * </p>
74 *
75 * @section PageSampleNvnSimple04_SectionPrecaution Precautions
76 * None.
77 *
78 * @section PageSampleNvnSimple04_SectionHowToExecute Execution Procedure
79 * Build the Visual Solution in the desired configuration and run it.
80 *
81 * @section PageSampleNvnSimple04_SectionDetail Description
82 * The first pass is implemented with the help of the SimplePrimitiveRenderer class that is in SharedLib.
83 *
84 * Illustrated in this demo is how to create and set color and depth textures to be renderered into,
85 * and how to use the color texture in a subsequent pass to render a textured primitive (the method
86 * of which is identical to TexturedCube). Two separate command buffers are used and submitted
87 * separately, one for each pass. This seems to be a sufficient mechanism to guarantee that the render
88 * texture is ready to be consumed by the second pass after it is produced by the first pass.
89 */
90
91
92
93#include <nn/fs.h>
94#include <nn/nn_Log.h>
95#include <nn/nn_Assert.h>
96#include <FileSystem.h>
97#include <GraphicsUtilities.h>
98#include <GraphicsStructures.h>
99#include <GraphicsRenderState.h>
100#include <SimpleFramework.h>
101#include "RenderToTexture.h"
102
103
104
105namespace
106{
107//-------------------------------------------------------------------------------------------------
108// Data structures
109//-------------------------------------------------------------------------------------------------
110class Vertex
111{
112public:
113 Vertex() NN_NOEXCEPT : m_Pos(), m_Uv() {}
114
115 const Vector3& GetPos() NN_NOEXCEPT
116 {
117 return m_Pos;
118 }
119
120 const Vector2& GetUv() NN_NOEXCEPT
121 {
122 return m_Uv;
123 }
124
125 void SetPos(float x, float y, float z) NN_NOEXCEPT
126 {
127 m_Pos.Set(x, y, z);
128 }
129
130 void SetUV(float u, float v) NN_NOEXCEPT
131 {
132 m_Uv.Set(u, v);
133 }
134
135private:
136 Vector3 m_Pos;
137 Vector2 m_Uv;
138};
139
140
141
142//-------------------------------------------------------------------------------------------------
143// Globals
144//-------------------------------------------------------------------------------------------------
145float g_VertexPositions[] =
146{
147 // front
148 -1.0f, 1.0f, 1.0f,
149 1.0f, 1.0f, 1.0f,
150 1.0f, -1.0f, 1.0f,
151 -1.0f, -1.0f, 1.0f,
152
153 // back
154 1.0f, 1.0f, -1.0f,
155 -1.0f, 1.0f, -1.0f,
156 -1.0f, -1.0f, -1.0f,
157 1.0f, -1.0f, -1.0f,
158
159 // left
160 1.0f, 1.0f, 1.0f,
161 1.0f, 1.0f, -1.0f,
162 1.0f, -1.0f, -1.0f,
163 1.0f, -1.0f, 1.0f,
164
165 // right
166 -1.0f, 1.0f, -1.0f,
167 -1.0f, 1.0f, 1.0f,
168 -1.0f, -1.0f, 1.0f,
169 -1.0f, -1.0f, -1.0f,
170};
171
172
173float g_VertexUvs[] =
174{
175 // front
176 0.0f, 0.0f,
177 1.0f, 0.0f,
178 1.0f, 1.0f,
179 0.0f, 1.0f,
180};
181
182
183uint32_t g_VertexIndices[] =
184{
185 0, 1, 2, 0, 2, 3
186};
187
188}
189
190
191
192//-------------------------------------------------------------------------------------------------
193// Public API
194//-------------------------------------------------------------------------------------------------
195void RenderToTexture::Initialize(GraphicsSystem* pGraphicsSystem) NN_NOEXCEPT
196{
197 if (!m_IsInitialized)
198 {
199 m_pGraphicsSystem = pGraphicsSystem;
200
201 //*****************************************************************************************************************
202 // from a rendering perspective, this demo is divided into two scene passes:
203 // 1) using SimplePrimitiveRenderer, render a scene to our own texture
204 // 2) take the texture, and render another scene with it, this time destined to be displayed to the device window
205 //*****************************************************************************************************************
206
207
208 // initialize shared memory pool to hold vertex data
209 size_t memPoolSize = 192 * 1024;
210 m_VertexMemPool.Initialize(m_pGraphicsSystem, nvn::MemoryPoolFlags::CPU_UNCACHED | nvn::MemoryPoolFlags::GPU_CACHED, memPoolSize, "RenderToTexture MemPool");
211
212
213 // initialize shared view transform
214 nn::util::Vector3f cameraPos(0, 0, 13);
215 nn::util::Vector3f targetPos(0, 0, 0);
216 nn::util::Vector3f up(0, 1, 0);
217
218 nn::util::MatrixLookAtRightHanded(&m_ViewMtx, cameraPos, targetPos, up);
219
220
221 // initialize shared render state
222 m_RenderState.Initialize();
223
224 m_RenderState.GetPolygonState()->SetFrontFace(nvn::FrontFace::CW);
225 m_RenderState.GetPolygonState()->SetCullFace(nvn::Face::BACK);
226 m_RenderState.GetPolygonState()->SetPolygonMode(nvn::PolygonMode::FILL);
227
228 m_RenderState.GetDepthStencilState()->SetDepthTestEnable(true);
229 m_RenderState.GetDepthStencilState()->SetDepthWriteEnable(true);
230 m_RenderState.GetDepthStencilState()->SetDepthFunc(nvn::DepthFunc::LESS);
231
232
233 // initialize pass-specific data
234 InitializeFirstPass();
235 InitializeSecondPass();
236
237
238 m_IsInitialized = true;
239 }
240}
241
242
243
244void RenderToTexture::DrawFrame() NN_NOEXCEPT
245{
246 UpdateFirstPass();
247 DrawFirstPass();
248
249 UpdateSecondPass();
250 DrawSecondPass();
251
252 m_IsScreenResolutionChanged = false;
253}
254
255
256
257void RenderToTexture::Finalize() NN_NOEXCEPT
258{
259 if (m_IsInitialized)
260 {
261 m_Shader.Finalize();
262
263 m_pGraphicsSystem->GetAllocator()->Free(m_GlslcData);
264
265 m_VertexDataBuffer.Finalize();
266 m_IndexDataBuffer.Finalize();
267 m_UniformDataBuffer.Finalize();
268
269 m_TextureManager.Finalize();
270
271 m_Cone.Destroy();
272 m_Octahedron.Destroy();
273
274 m_PrimitiveRenderer.Finalize();
275
276 m_VertexMemPool.Finalize(); // This memory pool is used by m_PrimitiveRenderer, so it must be finalized after m_PrimitiveRenderer.
277 // Otherwise, NVN Debug Layer will emit "Unfinalized object inside memory pool" errors for all
278 // the nvn::Buffers, etc. that are created internally by SimplePrimitiveRenderer.
279
280 for (int i = 0; i < NumRenderPasses; ++i)
281 {
282 m_CommandBuffer[i].Finalize();
283 }
284 m_pGraphicsSystem = nullptr;
285
286 m_IsInitialized = false;
287 }
288}
289
290
291
292//-------------------------------------------------------------------------------------------------
293// Private methods
294//-------------------------------------------------------------------------------------------------
295void RenderToTexture::InitializeFirstPass() NN_NOEXCEPT
296{
297 // initialize SimplePrimitiveRenderer for rendering first pass to texture
298 m_PrimitiveRenderer.Initialize(m_pGraphicsSystem, &m_VertexMemPool);
299
300 m_PrimitiveRenderer.UpdateAmbientColor(Color(0x111111));
301 m_PrimitiveRenderer.UpdateLightSettings(0, PointLightSettings(Color(0xffffff), Color(0x000000), nn::util::Vector3f(0, 1, 0), 0.001f));
302 m_PrimitiveRenderer.UpdateLightSettings(1, PointLightSettings(Color(0x000000), Color(0xffffff), nn::util::Vector3f(5, 3, 3), 0.0005f));
303
304
305 // create a few shape objects
306 m_NumPlanes = 20;
307 m_NumOctahedronInstances = 5 * m_NumPlanes;
308 m_NumConeInstances = 4 * m_NumPlanes;
309
310 m_Octahedron.CreateOctahedron(&m_PrimitiveRenderer, m_NumOctahedronInstances);
311 m_Octahedron.SetViewTransform(&m_ViewMtx);
312
313 m_Cone.CreateCone(&m_PrimitiveRenderer, m_NumConeInstances);
314 m_Cone.SetViewTransform(&m_ViewMtx);
315
316
317 // set materials for the shapes
318 MaterialSettings material(Color(0x222222), Color(0x000000), Color(0xeeeeee), Color(0x000000), 1.0f);
319
320 for (size_t i = 0; i < m_Octahedron.GetNumParts() / 2; ++i)
321 {
322 material.SetDiffuse(Color(0xa1e79e));
323 m_Octahedron.SetMaterial(2 * i, material);
324
325 material.SetDiffuse(Color(0xbbe7e8));
326 m_Octahedron.SetMaterial(2 * i + 1, material);
327 }
328
329 material.SetDiffuse(Color(0xf900cd));
330 m_Cone.SetMaterial(0, material);
331
332
333 // prepare our render (i.e. color) and depth textures:
334 int width = m_pGraphicsSystem->GetRenderTargetWidth();
335 int height = m_pGraphicsSystem->GetRenderTargetHeight();
336
337 // render texture configuration
338 nvn::TextureBuilder renderTextureBuilder;
339 renderTextureBuilder.SetDefaults()
340 .SetDevice(m_pGraphicsSystem->GetDevice())
341 .SetSize2D(width, height)
342 .SetTarget(nvn::TextureTarget::TARGET_2D)
343 .SetFormat(nvn::Format::RGBA8);
344
345 size_t renderTextureSize = renderTextureBuilder.GetStorageSize();
346 size_t renderTextureAlignment = renderTextureBuilder.GetStorageAlignment();
347
348 // depth texture configuration
349 nvn::TextureBuilder depthTextureBuilder;
350 depthTextureBuilder.SetDefaults()
351 .SetSize2D(width, height)
352 .SetDevice(m_pGraphicsSystem->GetDevice())
353 .SetTarget(nvn::TextureTarget::TARGET_2D)
354 .SetFormat(nvn::Format::DEPTH16)
355 .SetFlags(nvn::TextureFlags::COMPRESSIBLE); // necessary for depth textures
356
357 size_t depthTextureSize = depthTextureBuilder.GetStorageSize();
358 size_t depthTextureAlignment = depthTextureBuilder.GetStorageAlignment();
359
360
361 // initialize our texture manager and allocate storage for our render/depth textures
362 size_t textureAreaSize = renderTextureSize + renderTextureAlignment + depthTextureSize + depthTextureAlignment;
363
364 m_TextureManager.Initialize(m_pGraphicsSystem,
365 nvn::MemoryPoolFlags::CPU_UNCACHED | nvn::MemoryPoolFlags::GPU_CACHED | nvn::MemoryPoolFlags::COMPRESSIBLE,
366 32, textureAreaSize, "RenderToTexture Texture Pool");
367
368
369 // finish process of configuring/initializing/registering textures
370 int renderTextureId = InitializeTexture(renderTextureBuilder);
371 int depthTextureId = InitializeTexture(depthTextureBuilder);
372
373 m_pRenderTexture = m_TextureManager.GetTexture(renderTextureId);
374 m_pDepthTexture = m_TextureManager.GetTexture(depthTextureId);
375
376 nvn::SamplerBuilder samplerBuilder;
377 samplerBuilder.SetDefaults()
378 .SetDevice(m_pGraphicsSystem->GetDevice())
379 .SetMinMagFilter(nvn::MinFilter::LINEAR, nvn::MagFilter::LINEAR);
380
381 int samplerId = m_TextureManager.AddSampler(samplerBuilder);
382
383 m_RenderTextureHandle = m_TextureManager.RegisterTextureHandle(renderTextureId, samplerId);
384
385
386 // initialize command buffer
387 // Since the command set payload for rendering this pass is larger than the prior samples, we increase
388 // the commandMemoryChunkSize. The application will run fine even without doing so, but doing so will have the
389 // effect of reducing the number of times the command buffer memory callback is called during command set recording.
390
391 m_CommandBuffer[0].Initialize(m_pGraphicsSystem, false, 16 * 1024);
392
393 GenerateFirstPassCommandBuffer();
394}
395
396
397
398void RenderToTexture::InitializeSecondPass() NN_NOEXCEPT
399{
400 int64_t shaderBinFileSize = 0;
401
402 // read shader binary for second pass, create GraphicsShader object from it, and get uniform block reflection info
403 m_GlslcData = ReadFile(&shaderBinFileSize, "rom:/NvnSimple04.glslc", m_pGraphicsSystem->GetAllocator());
404
405 m_Shader.Initialize(m_pGraphicsSystem, static_cast<GLSLCoutput*>(m_GlslcData));
406
407 const UniformBlockInfo& uniformBlockInfo = m_Shader.LookupUniformBlockInfo("VertexShaderUniformBlock");
408
409
410 // allocate blocks of memory for vertex and uniform data
411 size_t attributeDataSize = NumVertices * sizeof(Vertex);
412 size_t indexDataSize = NumFaces * sizeof(g_VertexIndices);
413 size_t uniformAlignment = m_pGraphicsSystem->GetResourceInfo().uniformBufferAlignment;
414
415 m_VertexMemPool.AllocateBuffer(&m_VertexDataBuffer, attributeDataSize);
416 m_VertexMemPool.AllocateBuffer(&m_IndexDataBuffer, indexDataSize);
417 m_VertexMemPool.AllocateBuffer(&m_UniformDataBuffer, uniformBlockInfo.GetSize(), uniformAlignment);
418
419
420 // load vertex and index data into memory pool
421 Vertex* vertices = static_cast<Vertex*>(m_VertexDataBuffer.Map());
422
423 // we use a single vertex buffer with interleaved attributes
424 for (int i = 0; i < NumVertices; ++i)
425 {
426 Vertex* pVertex = vertices + i;
427
428 float x = g_VertexPositions[3 * i];
429 float y = g_VertexPositions[3 * i + 1];
430 float z = g_VertexPositions[3 * i + 2];
431
432 int uvIndex = i % NumFaces;
433 float u = g_VertexUvs[2 * uvIndex];
434 float v = g_VertexUvs[2 * uvIndex + 1];
435
436 pVertex->SetPos(x, y, z);
437 pVertex->SetUV(u, v);
438 }
439
440 UpdateTexcoords();
441
442 // indices
443 m_NumIndices = 6 * NumFaces;
444 uint32_t* indices = static_cast<uint32_t*>(m_IndexDataBuffer.Map());
445
446 for (uint32_t i = 0; i < m_NumIndices; ++i)
447 {
448 uint32_t delta = 4 * (i / 6);
449 uint32_t index = i % 6;
450
451 indices[i] = g_VertexIndices[index] + delta;
452 }
453
454
455 // compute and load uniform data for second pass into memory pool
456 char* baseUniformBlockAddr = static_cast<char*>(m_UniformDataBuffer.Map());
457
458 // load projection transform
459 char* projMtxAddr = baseUniformBlockAddr + uniformBlockInfo.LookupMemberInfo("projMtx").GetOffset();
460
461 nn::util::Matrix4x4fType projMtx;
462 nn::util::MatrixIdentity(&projMtx);
463 nn::util::MatrixPerspectiveFieldOfViewRightHanded(&projMtx, nn::util::FloatPi / 3.0f, 16.0f / 9.0f, 0.1f, 1000.0f);
464 LoadMatrix44(projMtxAddr, projMtx);
465
466 // compute model view transform location in memory pool
467 m_ModelViewMtxAddr = baseUniformBlockAddr + uniformBlockInfo.LookupMemberInfo("modelViewMtx").GetOffset();
468
469
470 // setup vertex attribute and stream state for second pass
471 const char* attributeNames[NumVertexAttributes];
472
473 // the ordering of the attribute names must logically match up with the attribute ordering in our vertex data structure (see above)
474 attributeNames[0] = "attr_position";
475 attributeNames[1] = "attr_uv";
476
477 SetupVertexAttribAndStreamStateInterleaved(attributeNames, NumVertexAttributes, m_Shader, m_VertexAttribStates, &m_VertexStreamState);
478
479
480 // uniform binding locations
481 m_VsUboLocation = uniformBlockInfo.GetBindingLocations(nvn::ShaderStage::VERTEX);
482 m_FsSamplerLocation = m_Shader.LookupUniformInfo("sampler").GetBindingLocations(nvn::ShaderStage::FRAGMENT);
483
484
485 // initialize command buffer
486 m_CommandBuffer[1].Initialize(m_pGraphicsSystem);
487
488 GenerateSecondPassCommandBuffer();
489}
490
491
492
493void RenderToTexture::UpdateFirstPass() NN_NOEXCEPT
494{
495 // update model view transforms for the shape instances
496 int octaIndex = 0;
497 int coneIndex = 0;
498 float dx = 8.0f;
499 float dy = 4.4f;
500 float coneAngle = atanf(dy / dx);
501
502 nn::util::Matrix4x3fType transformMtx;
503 nn::util::MatrixIdentity(&transformMtx);
504
505 for (int row = -1; row <= 1; ++row)
506 {
507 for (int col = -1; col <= 1; ++col)
508 {
509 float z = 0.0f;
510
511 nn::util::MatrixIdentity(&transformMtx);
512
513 // cones
514 if (abs(row) == abs(col) && (row != 0 && col != 0))
515 {
516 nn::util::MatrixSetRotateXyz(&transformMtx, nn::util::Vector3f(m_ShapeAngle, 0, 0));
517
518 float theta = ((nn::util::FloatPi / 2) + (row * coneAngle)) * col;
519
520 nn::util::Matrix4x3fType tempMtx;
521 nn::util::MatrixIdentity(&tempMtx);
522 nn::util::MatrixSetRotateXyz(&tempMtx, nn::util::Vector3f(0, 0, theta));
523
524 nn::util::MatrixMultiply(&transformMtx, transformMtx, tempMtx);
525
526 for (int i = 0; i < m_NumPlanes; ++i)
527 {
528 nn::util::MatrixSetTranslate(&transformMtx, nn::util::Vector3f(col * dx, row * dy, z));
529
530 m_Cone.SetModelTransform(coneIndex++, transformMtx);
531
532 z -= 5.0f;
533 }
534 }
535
536 // octahedrons
537 else
538 {
539 nn::util::MatrixSetRotateXyz(&transformMtx, nn::util::Vector3f(0, m_ShapeAngle, 0));
540
541 for (int i = 0; i < m_NumPlanes; ++i)
542 {
543 nn::util::MatrixSetTranslate(&transformMtx, nn::util::Vector3f(col * dx, row * dy, z));
544
545 m_Octahedron.SetModelTransform(octaIndex++, transformMtx);
546
547 z -= 5.0f;
548 }
549 }
550 }
551 }
552
553 // update state for next frame
554 m_ShapeAngle += 0.01f;
555
556 if (m_ShapeAngle > (2 * nn::util::FloatPi))
557 {
558 m_ShapeAngle -= (2 * nn::util::FloatPi);
559 m_PullbackAnimation = !m_PullbackAnimation;
560 }
561}
562
563
564
565void RenderToTexture::GenerateFirstPassCommandBuffer() NN_NOEXCEPT
566{
567 nvn::CommandBuffer* commandBuffer = m_CommandBuffer[0].StartRecording();
568 {
569 // first, we explicitly set our own render/depth texture here to render into
570 commandBuffer->SetRenderTargets(1, &m_pRenderTexture, nullptr, m_pDepthTexture, nullptr);
571
572 int width = m_pGraphicsSystem->GetScreenWidth();
573 int height = m_pGraphicsSystem->GetScreenHeight();
574
575 // we limit the scissor and viewport to a portion of the texture if screen resolution is less than 1080p.
576 // this will reduce GPU load under handheld mode, which runs at a lower GPU frequency.
577 commandBuffer->SetScissor(0, 0, width, height);
578 commandBuffer->SetViewport(0, 0, width, height);
579
580 Color clearColor(0x222222);
581
582 commandBuffer->ClearColor(0, clearColor.Get(), nvn::ClearColorMask::RGBA);
583 commandBuffer->ClearDepthStencil(1.0f, true, 0, 0);
584
585 m_RenderState.Bind(commandBuffer);
586
587 // draw our shapes:
588 m_PrimitiveRenderer.StartDrawing(commandBuffer);
589
590 // cones
591 m_Cone.StartDrawing(commandBuffer, 0);
592
593 for (int i = 0; i < m_NumConeInstances; ++i)
594 {
595 m_Cone.SetModelViewTransformAsCurrent(i);
596 m_Cone.Draw(commandBuffer);
597 }
598
599 // octahedrons
600 for (size_t p = 0; p < m_Octahedron.GetNumParts(); ++p)
601 {
602 m_Octahedron.StartDrawing(commandBuffer, p);
603
604 for (int i = 0; i < m_NumOctahedronInstances; ++i)
605 {
606 m_Octahedron.SetModelViewTransformAsCurrent(i);
607 m_Octahedron.Draw(commandBuffer);
608 }
609 }
610 }
611 m_CommandHandle[0] = m_CommandBuffer[0].EndRecording();
612}
613
614
615
616void RenderToTexture::DrawFirstPass() NN_NOEXCEPT
617{
618 if (!m_IsPrebuiltCommandBufferUsed || m_IsScreenResolutionChanged)
619 {
620 GenerateFirstPassCommandBuffer();
621 }
622 m_pGraphicsSystem->GetQueue()->SubmitCommands(1, &m_CommandHandle[0]);
623}
624
625
626
627void RenderToTexture::UpdateSecondPass() NN_NOEXCEPT
628{
629 // update modelView uniform
630 nn::util::Matrix4x3fType rotateMtx;
631 nn::util::Matrix4x3fType scaleMtx;
632 nn::util::Matrix4x3fType modelViewMtx;
633
634 nn::util::MatrixIdentity(&rotateMtx);
635 nn::util::MatrixSetRotateXyz(&rotateMtx, nn::util::Vector3f(0, m_BoxAngle, 0));
636
637 float scale = 3.705f;
638 nn::util::Vector3f scaleVec(16.0f / 9.0f * scale, scale, 16.0f / 9.0f * scale);
639 nn::util::MatrixIdentity(&scaleMtx);
640 nn::util::MatrixSetScale(&scaleMtx, scaleVec);
641
642 nn::util::MatrixMultiply(&modelViewMtx, scaleMtx, rotateMtx);
643 nn::util::MatrixSetTranslate(&modelViewMtx, nn::util::Vector3f(0, 0, m_BoxDepth));
644 nn::util::MatrixMultiply(&modelViewMtx, modelViewMtx, m_ViewMtx);
645
646 LoadMatrix43(m_ModelViewMtxAddr, modelViewMtx);
647
648 // update state for next frame
649 if (m_PullbackAnimation)
650 {
651 m_BoxDepth = -3.0f * (-cosf(m_ShapeAngle) + 1.0f);
652 m_BoxAngle = m_ShapeAngle / 2.0f;
653 }
654 else
655 {
656 m_BoxDepth = 0.0f;
657 m_BoxAngle = 0.0f;
658 }
659}
660
661
662
663void RenderToTexture::GenerateSecondPassCommandBuffer() NN_NOEXCEPT
664{
665 nvn::CommandBuffer* pCommandBuffer = m_CommandBuffer[1].StartRecording();
666 {
667 // scissor/viewport
668 m_pGraphicsSystem->SetDefaultViewportAndScissor(pCommandBuffer);
669
670 // clear color and depth/stencil buffers
671 Color clearColor(0xc4f0ff);
672
673 pCommandBuffer->ClearColor(0, clearColor.Get(), nvn::ClearColorMask::RGBA);
674 pCommandBuffer->ClearDepthStencil(1.0f, true, 0, 0);
675
676 // render state
677 m_RenderState.Bind(pCommandBuffer);
678
679 // bind shader
680 m_Shader.Bind(pCommandBuffer);
681
682 // bind uniform buffer
683 BindUniformBuffer(nvn::ShaderStage::VERTEX, m_VsUboLocation, &m_UniformDataBuffer, pCommandBuffer);
684
685 // bind vertex buffer data
686 pCommandBuffer->BindVertexAttribState(NumVertexAttributes, m_VertexAttribStates);
687 pCommandBuffer->BindVertexStreamState(1, &m_VertexStreamState);
688
689 BindVertexBuffer(0, &m_VertexDataBuffer, pCommandBuffer);
690
691 // set texture and sampler pools
692 m_TextureManager.SetTextureAndSamplerPools(pCommandBuffer);
693
694 // bind texture
695 pCommandBuffer->BindTexture(nvn::ShaderStage::FRAGMENT, m_FsSamplerLocation, m_RenderTextureHandle);
696
697 // draw call
698 pCommandBuffer->DrawElements(nvn::DrawPrimitive::TRIANGLES, nvn::IndexType::UNSIGNED_INT, m_NumIndices, m_IndexDataBuffer.GetAddress());
699 }
700
701 m_CommandHandle[1] = m_CommandBuffer[1].EndRecording();
702}
703
704
705
706void RenderToTexture::DrawSecondPass() NN_NOEXCEPT
707{
708 // we need to first reset the render target to the texture that the GraphicsSystem sends to the display
709 m_pGraphicsSystem->ResetRenderTarget();
710
711 if (!m_IsPrebuiltCommandBufferUsed || m_IsScreenResolutionChanged)
712 {
713 if (m_IsScreenResolutionChanged)
714 {
715 UpdateTexcoords();
716 }
717 GenerateSecondPassCommandBuffer();
718 }
719 m_pGraphicsSystem->GetQueue()->SubmitCommands(1, &m_CommandHandle[1]);
720}
721
722
723
724int RenderToTexture::InitializeTexture(nvn::TextureBuilder& textureBuilder) NN_NOEXCEPT
725{
726 size_t size = textureBuilder.GetStorageSize();
727 size_t alignment = textureBuilder.GetStorageAlignment();
728 ptrdiff_t memPoolOffset = 0;
729
730 void* cpuAddr = m_TextureManager.AllocateTextureMemory(&memPoolOffset, size, alignment);
731
732 textureBuilder.SetPackagedTextureData(cpuAddr);
733 textureBuilder.SetStorage(m_TextureManager.GetMemoryPool()->GetMemoryPool(), memPoolOffset);
734
735 return m_TextureManager.AddTexture(textureBuilder);
736}
737
738
739
740void RenderToTexture::UpdateTexcoords() NN_NOEXCEPT
741{
742 // This function update the texture coordinates of the second pass geometry that uses the
743 // first pass render texture. This can be used if the screen resolution has changed.
744 // Since we limit the viewport and scissor for the render texture based on the screen resolution
745 // as opposed to using different texture sizes for different screen size configurations,
746 // we also need to update the texture coordinates.
747
748 uint32_t screenWidth = m_pGraphicsSystem->GetScreenWidth();
749 uint32_t renderTextureWidth = m_pGraphicsSystem->GetRenderTargetWidth();
750
751 // note that we assume the aspect ratio is the same before/after change (hence we don't look at the height)
752
753 float uv = static_cast<float>(screenWidth) / static_cast<float>(renderTextureWidth);
754
755 if (m_pGraphicsSystem->GetScreenHeight() == 720)
756 {
757 uv = 0.666f; // seems to be a bit better in terms of the edges for 720p case
758 }
759
760 Vertex* vertices = static_cast<Vertex*>(m_VertexDataBuffer.Map());
761
762 for (int i = 0; i < NumVertices; ++i)
763 {
764 Vertex* pVertex = vertices + i;
765
766 if (pVertex->GetUv().GetX() != 0.0f)
767 {
768 pVertex->SetUV(uv, pVertex->GetUv().GetY());
769 }
770 if (pVertex->GetUv().GetY() != 0.0f)
771 {
772 pVertex->SetUV(pVertex->GetUv().GetX(), uv);
773 }
774 }
775}
776
777
778
779//-------------------------------------------------------------------------------------------------
780// main
781//-------------------------------------------------------------------------------------------------
782extern "C" void nnMain()
783{
784 RenderToTexture scene;
785
786 GraphicsSystemParams params;
787 params.SetShaderMemoryPoolSize(10 * 1024);
788 params.SetCommandBufferMemoryPoolSize(100 * 1024);
789
790 SimpleFrameworkMainWithDebugInfo(&scene, params, u8"RenderToTexture", Color(0xa0a0a0));
791}