summaryrefslogtreecommitdiffstats
path: root/Source/cmWorkerPool.h
blob: 40356501632b1f2dfbc21f914f7527b4b694e77f (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
/* Distributed under the OSI-approved BSD 3-Clause License.  See accompanying
   file Copyright.txt or https://cmake.org/licensing for details.  */
#pragma once

#include "cmConfigure.h" // IWYU pragma: keep

#include <cstdint>
#include <string>
#include <utility>
#include <vector>

#include <cm/memory>

// -- Types
class cmWorkerPoolInternal;

/** @class cmWorkerPool
 * @brief Thread pool with job queue
 */
class cmWorkerPool
{
public:
  /**
   * Return value and output of an external process.
   */
  struct ProcessResultT
  {
    void reset();
    bool error() const
    {
      return (this->ExitStatus != 0) || (this->TermSignal != 0) ||
        !this->ErrorMessage.empty();
    }

    std::int64_t ExitStatus = 0;
    int TermSignal = 0;
    std::string StdOut;
    std::string StdErr;
    std::string ErrorMessage;
  };

  /**
   * Abstract job class for concurrent job processing.
   */
  class JobT
  {
  public:
    JobT(JobT const&) = delete;
    JobT& operator=(JobT const&) = delete;

    /**
     * Virtual destructor.
     */
    virtual ~JobT();

    /**
     * Fence job flag
     *
     * Fence jobs require that:
     * - all jobs before in the queue have been processed
     * - no jobs later in the queue will be processed before this job was
     *   processed
     */
    bool IsFence() const { return this->Fence_; }

  protected:
    /**
     * Protected default constructor
     */
    JobT(bool fence = false)
      : Fence_(fence)
    {
    }

    /**
     * Abstract processing interface that must be implement in derived classes.
     */
    virtual void Process() = 0;

    /**
     * Get the worker pool.
     * Only valid during the JobT::Process() call!
     */
    cmWorkerPool* Pool() const { return this->Pool_; }

    /**
     * Get the user data.
     * Only valid during the JobT::Process() call!
     */
    void* UserData() const { return this->Pool_->UserData(); }

    /**
     * Get the worker index.
     * This is the index of the thread processing this job and is in the range
     * [0..ThreadCount).
     * Concurrently processing jobs will never have the same WorkerIndex().
     * Only valid during the JobT::Process() call!
     */
    unsigned int WorkerIndex() const { return this->WorkerIndex_; }

    /**
     * Run an external read only process.
     * Use only during JobT::Process() call!
     */
    bool RunProcess(ProcessResultT& result,
                    std::vector<std::string> const& command,
                    std::string const& workingDirectory);

  private:
    //! Needs access to Work()
    friend class cmWorkerPoolInternal;
    //! Worker thread entry method.
    void Work(cmWorkerPool* pool, unsigned int workerIndex)
    {
      this->Pool_ = pool;
      this->WorkerIndex_ = workerIndex;
      this->Process();
    }

    cmWorkerPool* Pool_ = nullptr;
    unsigned int WorkerIndex_ = 0;
    bool Fence_ = false;
  };

  /**
   * Job handle type
   */
  using JobHandleT = std::unique_ptr<JobT>;

  /**
   * Fence job base class
   */
  class JobFenceT : public JobT
  {
  public:
    JobFenceT()
      : JobT(true)
    {
    }
    //! Does nothing
    void Process() override {}
  };

  /**
   * Fence job that aborts the worker pool.
   *
   * Useful as the last job in the job queue.
   */
  class JobEndT : JobFenceT
  {
  public:
    //! Does nothing
    void Process() override { this->Pool()->Abort(); }
  };

  // -- Methods
  cmWorkerPool();
  ~cmWorkerPool();

  /**
   * Number of worker threads.
   */
  unsigned int ThreadCount() const { return this->ThreadCount_; }

  /**
   * Set the number of worker threads.
   *
   * Calling this method during Process() has no effect.
   */
  void SetThreadCount(unsigned int threadCount);

  /**
   * Blocking function that starts threads to process all Jobs in the queue.
   *
   * This method blocks until a job calls the Abort() method.
   * @arg threadCount Number of threads to process jobs.
   * @arg userData Common user data pointer available in all Jobs.
   */
  bool Process(void* userData = nullptr);

  /**
   * User data reference passed to Process().
   *
   * Only valid during Process().
   */
  void* UserData() const { return this->UserData_; }

  // -- Job processing interface

  /**
   * Clears the job queue and aborts all worker threads.
   *
   * This method is thread safe and can be called from inside a job.
   */
  void Abort();

  /**
   * Push job to the queue.
   *
   * This method is thread safe and can be called from inside a job or before
   * Process().
   */
  bool PushJob(JobHandleT&& jobHandle);

  /**
   * Push job to the queue
   *
   * This method is thread safe and can be called from inside a job or before
   * Process().
   */
  template <class T, typename... Args>
  bool EmplaceJob(Args&&... args)
  {
    return this->PushJob(cm::make_unique<T>(std::forward<Args>(args)...));
  }

private:
  void* UserData_ = nullptr;
  unsigned int ThreadCount_ = 1;
  std::unique_ptr<cmWorkerPoolInternal> Int_;
};
(PACKAGE_GUID "6514377e-dfd4-4cdb-80df-4e0366346efc")
+
+if (NOT "${PLATFORM}" STREQUAL "DESKTOP")
+ configure_file(
+ cmake/Package_vc${COMPILER_VERSION}.${PLATFORM}.appxmanifest.in
+ ${CMAKE_CURRENT_BINARY_DIR}/${APP_MANIFEST_NAME}
+ @ONLY)
+endif()
+
+set(SOURCE_FILES
+ Direct3DApp1/CubeRenderer.cpp
+ Direct3DApp1/Direct3DApp1.cpp
+ Direct3DApp1/Direct3DBase.cpp
+ Direct3DApp1/pch.cpp
+ )
+
+set(HEADER_FILES
+ Direct3DApp1/BasicTimer.h
+ Direct3DApp1/CubeRenderer.h
+ Direct3DApp1/Direct3DApp1.h
+ Direct3DApp1/Direct3DBase.h
+ Direct3DApp1/DirectXHelper.h
+ Direct3DApp1/pch.h
+ )
+
+set(PIXELSHADER_FILES
+ Direct3DApp1/SimplePixelShader.hlsl
+ )
+
+set(VERTEXSHADER_FILES
+ Direct3DApp1/SimpleVertexShader.hlsl
+ )
+
+set(CONTENT_FILES ${PIXELSHADER_FILES} ${VERTEXSHADER_FILES})
+
+if (WINDOWS_PHONE8)
+ set(CONTENT_FILES ${CONTENT_FILES}
+ ${CMAKE_CURRENT_BINARY_DIR}/${APP_MANIFEST_NAME}
+ Direct3DApp1/Assets/Tiles/FlipCycleTileLarge.png
+ Direct3DApp1/Assets/Tiles/FlipCycleTileMedium.png
+ Direct3DApp1/Assets/Tiles/FlipCycleTileSmall.png
+ Direct3DApp1/Assets/Tiles/IconicTileMediumLarge.png
+ Direct3DApp1/Assets/Tiles/IconicTileSmall.png
+ Direct3DApp1/Assets/ApplicationIcon.png
+ )
+ # Windows Phone 8.0 needs to copy all the images.
+ # It doesn't know to use relative paths.
+ file(COPY
+ Direct3DApp1/Assets/Tiles/FlipCycleTileLarge.png
+ Direct3DApp1/Assets/Tiles/FlipCycleTileMedium.png
+ Direct3DApp1/Assets/Tiles/FlipCycleTileSmall.png
+ Direct3DApp1/Assets/Tiles/IconicTileMediumLarge.png
+ Direct3DApp1/Assets/Tiles/IconicTileSmall.png
+ Direct3DApp1/Assets/ApplicationIcon.png
+ DESTINATION ${CMAKE_CURRENT_BINARY_DIR}
+ )
+
+elseif (NOT "${PLATFORM}" STREQUAL "DESKTOP")
+ set(CONTENT_FILES ${CONTENT_FILES}
+ ${CMAKE_CURRENT_BINARY_DIR}/${APP_MANIFEST_NAME}
+ Direct3DApp1/Assets/Logo.png
+ Direct3DApp1/Assets/SmallLogo.png
+ Direct3DApp1/Assets/SplashScreen.png
+ Direct3DApp1/Assets/StoreLogo.png
+ )
+endif()
+
+set(RESOURCE_FILES
+ ${CONTENT_FILES} ${DEBUG_CONTENT_FILES} ${RELEASE_CONTENT_FILES}
+ Direct3DApp1/Direct3DApp1_TemporaryKey.pfx)
+
+set_property(SOURCE ${CONTENT_FILES} PROPERTY VS_DEPLOYMENT_CONTENT 1)
+set_property(SOURCE ${DEBUG_CONTENT_FILES} PROPERTY VS_DEPLOYMENT_CONTENT $<CONFIG:Debug>)
+set_property(SOURCE ${RELEASE_CONTENT_FILES} PROPERTY
+ VS_DEPLOYMENT_CONTENT $<OR:$<CONFIG:Release>,$<CONFIG:RelWithDebInfo>,$<CONFIG:MinSizeRel>>)
+
+set_property(SOURCE ${PIXELSHADER_FILES} PROPERTY VS_SHADER_TYPE Pixel)
+set_property(SOURCE ${VERTEXSHADER_FILES} PROPERTY VS_SHADER_TYPE Vertex)
+
+source_group("Source Files" FILES ${SOURCE_FILES})
+source_group("Header Files" FILES ${HEADER_FILES})
+source_group("Resource Files" FILES ${RESOURCE_FILES})
+
+add_executable(${EXE_NAME} WIN32 ${SOURCE_FILES} ${HEADER_FILES} ${RESOURCE_FILES})
+set_property(TARGET ${EXE_NAME} PROPERTY VS_WINRT_COMPONENT TRUE)
+target_link_libraries(${EXE_NAME} d3d11)
diff --git a/Tests/VSWinStorePhone/Direct3DApp1/Assets/ApplicationIcon.png b/Tests/VSWinStorePhone/Direct3DApp1/Assets/ApplicationIcon.png
new file mode 100644
index 0000000..7d95d4e
--- /dev/null
+++ b/Tests/VSWinStorePhone/Direct3DApp1/Assets/ApplicationIcon.png
Binary files differ
diff --git a/Tests/VSWinStorePhone/Direct3DApp1/Assets/Logo.png b/Tests/VSWinStorePhone/Direct3DApp1/Assets/Logo.png
new file mode 100644
index 0000000..e26771c
--- /dev/null
+++ b/Tests/VSWinStorePhone/Direct3DApp1/Assets/Logo.png
Binary files differ
diff --git a/Tests/VSWinStorePhone/Direct3DApp1/Assets/SmallLogo.png b/Tests/VSWinStorePhone/Direct3DApp1/Assets/SmallLogo.png
new file mode 100644
index 0000000..1eb0d9d
--- /dev/null
+++ b/Tests/VSWinStorePhone/Direct3DApp1/Assets/SmallLogo.png
Binary files differ
diff --git a/Tests/VSWinStorePhone/Direct3DApp1/Assets/SplashScreen.png b/Tests/VSWinStorePhone/Direct3DApp1/Assets/SplashScreen.png
new file mode 100644
index 0000000..c951e03
--- /dev/null
+++ b/Tests/VSWinStorePhone/Direct3DApp1/Assets/SplashScreen.png
Binary files differ
diff --git a/Tests/VSWinStorePhone/Direct3DApp1/Assets/StoreLogo.png b/Tests/VSWinStorePhone/Direct3DApp1/Assets/StoreLogo.png
new file mode 100644
index 0000000..dcb6727
--- /dev/null
+++ b/Tests/VSWinStorePhone/Direct3DApp1/Assets/StoreLogo.png
Binary files differ
diff --git a/Tests/VSWinStorePhone/Direct3DApp1/Assets/Tiles/FlipCycleTileLarge.png b/Tests/VSWinStorePhone/Direct3DApp1/Assets/Tiles/FlipCycleTileLarge.png
new file mode 100644
index 0000000..e0c59ac
--- /dev/null
+++ b/Tests/VSWinStorePhone/Direct3DApp1/Assets/Tiles/FlipCycleTileLarge.png
Binary files differ
diff --git a/Tests/VSWinStorePhone/Direct3DApp1/Assets/Tiles/FlipCycleTileMedium.png b/Tests/VSWinStorePhone/Direct3DApp1/Assets/Tiles/FlipCycleTileMedium.png
new file mode 100644
index 0000000..e93b89d
--- /dev/null
+++ b/Tests/VSWinStorePhone/Direct3DApp1/Assets/Tiles/FlipCycleTileMedium.png
Binary files differ
diff --git a/Tests/VSWinStorePhone/Direct3DApp1/Assets/Tiles/FlipCycleTileSmall.png b/Tests/VSWinStorePhone/Direct3DApp1/Assets/Tiles/FlipCycleTileSmall.png
new file mode 100644
index 0000000..550b1b5
--- /dev/null
+++ b/Tests/VSWinStorePhone/Direct3DApp1/Assets/Tiles/FlipCycleTileSmall.png
Binary files differ
diff --git a/Tests/VSWinStorePhone/Direct3DApp1/Assets/Tiles/IconicTileMediumLarge.png b/Tests/VSWinStorePhone/Direct3DApp1/Assets/Tiles/IconicTileMediumLarge.png
new file mode 100644
index 0000000..686e6b5
--- /dev/null
+++ b/Tests/VSWinStorePhone/Direct3DApp1/Assets/Tiles/IconicTileMediumLarge.png
Binary files differ
diff --git a/Tests/VSWinStorePhone/Direct3DApp1/Assets/Tiles/IconicTileSmall.png b/Tests/VSWinStorePhone/Direct3DApp1/Assets/Tiles/IconicTileSmall.png
new file mode 100644
index 0000000..d4b5ede
--- /dev/null
+++ b/Tests/VSWinStorePhone/Direct3DApp1/Assets/Tiles/IconicTileSmall.png
Binary files differ
diff --git a/Tests/VSWinStorePhone/Direct3DApp1/BasicTimer.h b/Tests/VSWinStorePhone/Direct3DApp1/BasicTimer.h
new file mode 100644
index 0000000..b58c77d
--- /dev/null
+++ b/Tests/VSWinStorePhone/Direct3DApp1/BasicTimer.h
@@ -0,0 +1,76 @@
+#pragma once
+
+#include <wrl.h>
+
+// Helper class for basic timing.
+ref class BasicTimer sealed
+{
+public:
+ // Initializes internal timer values.
+ BasicTimer()
+ {
+ if (!QueryPerformanceFrequency(&m_frequency))
+ {
+ throw ref new Platform::FailureException();
+ }
+ Reset();
+ }
+
+ // Reset the timer to initial values.
+ void Reset()
+ {
+ Update();
+ m_startTime = m_currentTime;
+ m_total = 0.0f;
+ m_delta = 1.0f / 60.0f;
+ }
+
+ // Update the timer's internal values.
+ void Update()
+ {
+ if (!QueryPerformanceCounter(&m_currentTime))
+ {
+ throw ref new Platform::FailureException();
+ }
+
+ m_total = static_cast<float>(
+ static_cast<double>(m_currentTime.QuadPart - m_startTime.QuadPart) /
+ static_cast<double>(m_frequency.QuadPart)
+ );
+
+ if (m_lastTime.QuadPart == m_startTime.QuadPart)
+ {
+ // If the timer was just reset, report a time delta equivalent to 60Hz frame time.
+ m_delta = 1.0f / 60.0f;
+ }
+ else
+ {
+ m_delta = static_cast<float>(
+ static_cast<double>(m_currentTime.QuadPart - m_lastTime.QuadPart) /
+ static_cast<double>(m_frequency.QuadPart)
+ );
+ }
+
+ m_lastTime = m_currentTime;
+ }
+
+ // Duration in seconds between the last call to Reset() and the last call to Update().
+ property float Total
+ {
+ float get() { return m_total; }
+ }
+
+ // Duration in seconds between the previous two calls to Update().
+ property float Delta
+ {
+ float get() { return m_delta; }
+ }
+
+private:
+ LARGE_INTEGER m_frequency;
+ LARGE_INTEGER m_currentTime;
+ LARGE_INTEGER m_startTime;
+ LARGE_INTEGER m_lastTime;
+ float m_total;
+ float m_delta;
+};
diff --git a/Tests/VSWinStorePhone/Direct3DApp1/CubeRenderer.cpp b/Tests/VSWinStorePhone/Direct3DApp1/CubeRenderer.cpp
new file mode 100644
index 0000000..f4827f2
--- /dev/null
+++ b/Tests/VSWinStorePhone/Direct3DApp1/CubeRenderer.cpp
@@ -0,0 +1,260 @@
+#include "pch.h"
+#include "CubeRenderer.h"
+
+using namespace DirectX;
+using namespace Microsoft::WRL;
+using namespace Windows::Foundation;
+using namespace Windows::UI::Core;
+
+CubeRenderer::CubeRenderer() :
+ m_loadingComplete(false),
+ m_indexCount(0)
+{
+}
+
+void CubeRenderer::CreateDeviceResources()
+{
+ Direct3DBase::CreateDeviceResources();
+
+ auto loadVSTask = DX::ReadDataAsync("SimpleVertexShader.cso");
+ auto loadPSTask = DX::ReadDataAsync("SimplePixelShader.cso");
+
+ auto createVSTask = loadVSTask.then([this](Platform::Array<byte>^ fileData) {
+ DX::ThrowIfFailed(
+ m_d3dDevice->CreateVertexShader(
+ fileData->Data,
+ fileData->Length,
+ nullptr,
+ &m_vertexShader
+ )
+ );
+
+ const D3D11_INPUT_ELEMENT_DESC vertexDesc[] =
+ {
+ { "POSITION", 0, DXGI_FORMAT_R32G32B32_FLOAT, 0, 0, D3D11_INPUT_PER_VERTEX_DATA, 0 },
+ { "COLOR", 0, DXGI_FORMAT_R32G32B32_FLOAT, 0, 12, D3D11_INPUT_PER_VERTEX_DATA, 0 },
+ };
+
+ DX::ThrowIfFailed(
+ m_d3dDevice->CreateInputLayout(
+ vertexDesc,
+ ARRAYSIZE(vertexDesc),
+ fileData->Data,
+ fileData->Length,
+ &m_inputLayout
+ )
+ );
+ });
+
+ auto createPSTask = loadPSTask.then([this](Platform::Array<byte>^ fileData) {
+ DX::ThrowIfFailed(
+ m_d3dDevice->CreatePixelShader(
+ fileData->Data,
+ fileData->Length,
+ nullptr,
+ &m_pixelShader
+ )
+ );
+
+ CD3D11_BUFFER_DESC constantBufferDesc(sizeof(ModelViewProjectionConstantBuffer), D3D11_BIND_CONSTANT_BUFFER);
+ DX::ThrowIfFailed(
+ m_d3dDevice->CreateBuffer(
+ &constantBufferDesc,
+ nullptr,
+ &m_constantBuffer
+ )
+ );
+ });
+
+ auto createCubeTask = (createPSTask && createVSTask).then([this] () {
+ VertexPositionColor cubeVertices[] =
+ {
+ {XMFLOAT3(-0.5f, -0.5f, -0.5f), XMFLOAT3(0.0f, 0.0f, 0.0f)},
+ {XMFLOAT3(-0.5f, -0.5f, 0.5f), XMFLOAT3(0.0f, 0.0f, 1.0f)},
+ {XMFLOAT3(-0.5f, 0.5f, -0.5f), XMFLOAT3(0.0f, 1.0f, 0.0f)},
+ {XMFLOAT3(-0.5f, 0.5f, 0.5f), XMFLOAT3(0.0f, 1.0f, 1.0f)},
+ {XMFLOAT3( 0.5f, -0.5f, -0.5f), XMFLOAT3(1.0f, 0.0f, 0.0f)},
+ {XMFLOAT3( 0.5f, -0.5f, 0.5f), XMFLOAT3(1.0f, 0.0f, 1.0f)},
+ {XMFLOAT3( 0.5f, 0.5f, -0.5f), XMFLOAT3(1.0f, 1.0f, 0.0f)},
+ {XMFLOAT3( 0.5f, 0.5f, 0.5f), XMFLOAT3(1.0f, 1.0f, 1.0f)},
+ };
+
+ D3D11_SUBRESOURCE_DATA vertexBufferData = {0};
+ vertexBufferData.pSysMem = cubeVertices;
+ vertexBufferData.SysMemPitch = 0;
+ vertexBufferData.SysMemSlicePitch = 0;
+ CD3D11_BUFFER_DESC vertexBufferDesc(sizeof(cubeVertices), D3D11_BIND_VERTEX_BUFFER);
+ DX::ThrowIfFailed(
+ m_d3dDevice->CreateBuffer(
+ &vertexBufferDesc,
+ &vertexBufferData,
+ &m_vertexBuffer
+ )
+ );
+
+ unsigned short cubeIndices[] =
+ {
+ 0,2,1, // -x
+ 1,2,3,
+
+ 4,5,6, // +x
+ 5,7,6,
+
+ 0,1,5, // -y
+ 0,5,4,
+
+ 2,6,7, // +y
+ 2,7,3,
+
+ 0,4,6, // -z
+ 0,6,2,
+
+ 1,3,7, // +z
+ 1,7,5,
+ };
+
+ m_indexCount = ARRAYSIZE(cubeIndices);
+
+ D3D11_SUBRESOURCE_DATA indexBufferData = {0};
+ indexBufferData.pSysMem = cubeIndices;
+ indexBufferData.SysMemPitch = 0;
+ indexBufferData.SysMemSlicePitch = 0;
+ CD3D11_BUFFER_DESC indexBufferDesc(sizeof(cubeIndices), D3D11_BIND_INDEX_BUFFER);
+ DX::ThrowIfFailed(
+ m_d3dDevice->CreateBuffer(
+ &indexBufferDesc,
+ &indexBufferData,
+ &m_indexBuffer
+ )
+ );
+ });
+
+ createCubeTask.then([this] () {
+ m_loadingComplete = true;
+ });
+}
+
+void CubeRenderer::CreateWindowSizeDependentResources()
+{
+ Direct3DBase::CreateWindowSizeDependentResources();
+
+ float aspectRatio = m_windowBounds.Width / m_windowBounds.Height;
+ float fovAngleY = 70.0f * XM_PI / 180.0f;
+ if (aspectRatio < 1.0f)
+ {
+ fovAngleY /= aspectRatio;
+ }
+
+ // Note that the m_orientationTransform3D matrix is post-multiplied here
+ // in order to correctly orient the scene to match the display orientation.
+ // This post-multiplication step is required for any draw calls that are
+ // made to the swap chain render target. For draw calls to other targets,
+ // this transform should not be applied.
+ XMStoreFloat4x4(
+ &m_constantBufferData.projection,
+ XMMatrixTranspose(
+ XMMatrixMultiply(
+ XMMatrixPerspectiveFovRH(
+ fovAngleY,
+ aspectRatio,
+ 0.01f,
+ 100.0f
+ ),
+ XMLoadFloat4x4(&m_orientationTransform3D)
+ )
+ )
+ );
+}
+
+void CubeRenderer::Update(float timeTotal, float timeDelta)
+{
+ (void) timeDelta; // Unused parameter.
+
+ XMVECTOR eye = XMVectorSet(0.0f, 0.7f, 1.5f, 0.0f);
+ XMVECTOR at = XMVectorSet(0.0f, -0.1f, 0.0f, 0.0f);
+ XMVECTOR up = XMVectorSet(0.0f, 1.0f, 0.0f, 0.0f);
+
+ XMStoreFloat4x4(&m_constantBufferData.view, XMMatrixTranspose(XMMatrixLookAtRH(eye, at, up)));
+ XMStoreFloat4x4(&m_constantBufferData.model, XMMatrixTranspose(XMMatrixRotationY(timeTotal * XM_PIDIV4)));
+}
+
+void CubeRenderer::Render()
+{
+ const float midnightBlue[] = { 0.098f, 0.098f, 0.439f, 1.000f };
+ m_d3dContext->ClearRenderTargetView(
+ m_renderTargetView.Get(),
+ midnightBlue
+ );
+
+ m_d3dContext->ClearDepthStencilView(
+ m_depthStencilView.Get(),
+ D3D11_CLEAR_DEPTH,
+ 1.0f,
+ 0
+ );
+
+ // Only draw the cube once it is loaded (loading is asynchronous).
+ if (!m_loadingComplete)
+ {
+ return;
+ }
+
+ m_d3dContext->OMSetRenderTargets(
+ 1,
+ m_renderTargetView.GetAddressOf(),
+ m_depthStencilView.Get()
+ );
+
+ m_d3dContext->UpdateSubresource(
+ m_constantBuffer.Get(),
+ 0,
+ NULL,
+ &m_constantBufferData,
+ 0,
+ 0
+ );
+
+ UINT stride = sizeof(VertexPositionColor);
+ UINT offset = 0;
+ m_d3dContext->IASetVertexBuffers(
+ 0,
+ 1,
+ m_vertexBuffer.GetAddressOf(),
+ &stride,
+ &offset
+ );
+
+ m_d3dContext->IASetIndexBuffer(
+ m_indexBuffer.Get(),
+ DXGI_FORMAT_R16_UINT,
+ 0
+ );
+
+ m_d3dContext->IASetPrimitiveTopology(D3D11_PRIMITIVE_TOPOLOGY_TRIANGLELIST);
+
+ m_d3dContext->IASetInputLayout(m_inputLayout.Get());
+
+ m_d3dContext->VSSetShader(
+ m_vertexShader.Get(),
+ nullptr,
+ 0
+ );
+
+ m_d3dContext->VSSetConstantBuffers(
+ 0,
+ 1,
+ m_constantBuffer.GetAddressOf()
+ );
+
+ m_d3dContext->PSSetShader(
+ m_pixelShader.Get(),
+ nullptr,
+ 0
+ );
+
+ m_d3dContext->DrawIndexed(
+ m_indexCount,
+ 0,
+ 0
+ );
+}
diff --git a/Tests/VSWinStorePhone/Direct3DApp1/CubeRenderer.h b/Tests/VSWinStorePhone/Direct3DApp1/CubeRenderer.h
new file mode 100644
index 0000000..68cb188
--- /dev/null
+++ b/Tests/VSWinStorePhone/Direct3DApp1/CubeRenderer.h
@@ -0,0 +1,44 @@
+#pragma once
+
+#include "Direct3DBase.h"
+
+struct ModelViewProjectionConstantBuffer
+{
+ DirectX::XMFLOAT4X4 model;
+ DirectX::XMFLOAT4X4 view;
+ DirectX::XMFLOAT4X4 projection;
+};
+
+struct VertexPositionColor
+{
+ DirectX::XMFLOAT3 pos;
+ DirectX::XMFLOAT3 color;
+};
+
+// This class renders a simple spinning cube.
+ref class CubeRenderer sealed : public Direct3DBase
+{
+public:
+ CubeRenderer();
+
+ // Direct3DBase methods.
+ virtual void CreateDeviceResources() override;
+ virtual void CreateWindowSizeDependentResources() override;
+ virtual void Render() override;
+
+ // Method for updating time-dependent objects.
+ void Update(float timeTotal, float timeDelta);
+
+private:
+ bool m_loadingComplete;
+
+ Microsoft::WRL::ComPtr<ID3D11InputLayout> m_inputLayout;
+ Microsoft::WRL::ComPtr<ID3D11Buffer> m_vertexBuffer;
+ Microsoft::WRL::ComPtr<ID3D11Buffer> m_indexBuffer;
+ Microsoft::WRL::ComPtr<ID3D11VertexShader> m_vertexShader;
+ Microsoft::WRL::ComPtr<ID3D11PixelShader> m_pixelShader;
+ Microsoft::WRL::ComPtr<ID3D11Buffer> m_constantBuffer;
+
+ uint32 m_indexCount;
+ ModelViewProjectionConstantBuffer m_constantBufferData;
+};
diff --git a/Tests/VSWinStorePhone/Direct3DApp1/Direct3DApp1.cpp b/Tests/VSWinStorePhone/Direct3DApp1/Direct3DApp1.cpp
new file mode 100644
index 0000000..3dbb97f
--- /dev/null
+++ b/Tests/VSWinStorePhone/Direct3DApp1/Direct3DApp1.cpp
@@ -0,0 +1,153 @@
+#include "pch.h"
+#include "Direct3DApp1.h"
+#include "BasicTimer.h"
+
+using namespace Windows::ApplicationModel;
+using namespace Windows::ApplicationModel::Core;
+using namespace Windows::ApplicationModel::Activation;
+using namespace Windows::UI::Core;
+using namespace Windows::System;
+using namespace Windows::Foundation;
+using namespace Windows::Graphics::Display;
+using namespace concurrency;
+
+Direct3DApp1::Direct3DApp1() :
+ m_windowClosed(false),
+ m_windowVisible(true)
+{
+}
+
+void Direct3DApp1::Initialize(CoreApplicationView^ applicationView)
+{
+ applicationView->Activated +=
+ ref new TypedEventHandler<CoreApplicationView^, IActivatedEventArgs^>(this, &Direct3DApp1::OnActivated);
+
+ CoreApplication::Suspending +=
+ ref new EventHandler<SuspendingEventArgs^>(this, &Direct3DApp1::OnSuspending);
+
+ CoreApplication::Resuming +=
+ ref new EventHandler<Platform::Object^>(this, &Direct3DApp1::OnResuming);
+
+ m_renderer = ref new CubeRenderer();
+}
+
+void Direct3DApp1::SetWindow(CoreWindow^ window)
+{
+ window->SizeChanged +=
+ ref new TypedEventHandler<CoreWindow^, WindowSizeChangedEventArgs^>(this, &Direct3DApp1::OnWindowSizeChanged);
+
+ window->VisibilityChanged +=
+ ref new TypedEventHandler<CoreWindow^, VisibilityChangedEventArgs^>(this, &Direct3DApp1::OnVisibilityChanged);
+
+ window->Closed +=
+ ref new TypedEventHandler<CoreWindow^, CoreWindowEventArgs^>(this, &Direct3DApp1::OnWindowClosed);
+
+#ifndef PHONE
+ window->PointerCursor = ref new CoreCursor(CoreCursorType::Arrow, 0);
+#endif
+
+ window->PointerPressed +=
+ ref new TypedEventHandler<CoreWindow^, PointerEventArgs^>(this, &Direct3DApp1::OnPointerPressed);
+
+ window->PointerMoved +=
+ ref new TypedEventHandler<CoreWindow^, PointerEventArgs^>(this, &Direct3DApp1::OnPointerMoved);
+
+ m_renderer->Initialize(CoreWindow::GetForCurrentThread());
+}
+
+void Direct3DApp1::Load(Platform::String^ entryPoint)
+{
+}
+
+void Direct3DApp1::Run()
+{
+ BasicTimer^ timer = ref new BasicTimer();
+
+ while (!m_windowClosed)
+ {
+ if (m_windowVisible)
+ {
+ timer->Update();
+ CoreWindow::GetForCurrentThread()->Dispatcher->ProcessEvents(CoreProcessEventsOption::ProcessAllIfPresent);
+ m_renderer->Update(timer->Total, timer->Delta);
+ m_renderer->Render();
+ m_renderer->Present(); // This call is synchronized to the display frame rate.
+ }
+ else
+ {
+ CoreWindow::GetForCurrentThread()->Dispatcher->ProcessEvents(CoreProcessEventsOption::ProcessOneAndAllPending);
+ }
+ }
+}
+
+void Direct3DApp1::Uninitialize()
+{
+}
+
+void Direct3DApp1::OnWindowSizeChanged(CoreWindow^ sender, WindowSizeChangedEventArgs^ args)
+{
+ m_renderer->UpdateForWindowSizeChange();
+}
+
+void Direct3DApp1::OnVisibilityChanged(CoreWindow^ sender, VisibilityChangedEventArgs^ args)
+{
+ m_windowVisible = args->Visible;
+}
+
+void Direct3DApp1::OnWindowClosed(CoreWindow^ sender, CoreWindowEventArgs^ args)
+{
+ m_windowClosed = true;
+}
+
+void Direct3DApp1::OnPointerPressed(CoreWindow^ sender, PointerEventArgs^ args)
+{
+ // Insert your code here.
+}
+
+void Direct3DApp1::OnPointerMoved(CoreWindow^ sender, PointerEventArgs^ args)
+{
+ // Insert your code here.
+}
+
+void Direct3DApp1::OnActivated(CoreApplicationView^ applicationView, IActivatedEventArgs^ args)
+{
+ CoreWindow::GetForCurrentThread()->Activate();
+}
+
+void Direct3DApp1::OnSuspending(Platform::Object^ sender, SuspendingEventArgs^ args)
+{
+ // Save app state asynchronously after requesting a deferral. Holding a deferral
+ // indicates that the application is busy performing suspending operations. Be
+ // aware that a deferral may not be held indefinitely. After about five seconds,
+ // the app will be forced to exit.
+ SuspendingDeferral^ deferral = args->SuspendingOperation->GetDeferral();
+ m_renderer->ReleaseResourcesForSuspending();
+
+ create_task([this, deferral]()
+ {
+ // Insert your code here.
+
+ deferral->Complete();
+ });
+}
+
+void Direct3DApp1::OnResuming(Platform::Object^ sender, Platform::Object^ args)
+{
+ // Restore any data or state that was unloaded on suspend. By default, data
+ // and state are persisted when resuming from suspend. Note that this event
+ // does not occur if the app was previously terminated.
+ m_renderer->CreateWindowSizeDependentResources();
+}
+
+IFrameworkView^ Direct3DApplicationSource::CreateView()
+{
+ return ref new Direct3DApp1();
+}
+
+[Platform::MTAThread]
+int main(Platform::Array<Platform::String^>^)
+{
+ auto direct3DApplicationSource = ref new Direct3DApplicationSource();
+ CoreApplication::Run(direct3DApplicationSource);
+ return 0;
+}
diff --git a/Tests/VSWinStorePhone/Direct3DApp1/Direct3DApp1.h b/Tests/VSWinStorePhone/Direct3DApp1/Direct3DApp1.h
new file mode 100644
index 0000000..40b69a1
--- /dev/null
+++ b/Tests/VSWinStorePhone/Direct3DApp1/Direct3DApp1.h
@@ -0,0 +1,40 @@
+#pragma once
+
+#include "pch.h"
+#include "CubeRenderer.h"
+
+ref class Direct3DApp1 sealed : public Windows::ApplicationModel::Core::IFrameworkView
+{
+public:
+ Direct3DApp1();
+
+ // IFrameworkView Methods.
+ virtual void Initialize(Windows::ApplicationModel::Core::CoreApplicationView^ applicationView);
+ virtual void SetWindow(Windows::UI::Core::CoreWindow^ window);
+ virtual void Load(Platform::String^ entryPoint);
+ virtual void Run();
+ virtual void Uninitialize();
+
+protected:
+ // Event Handlers.
+ void OnWindowSizeChanged(Windows::UI::Core::CoreWindow^ sender, Windows::UI::Core::WindowSizeChangedEventArgs^ args);
+ void OnLogicalDpiChanged(Platform::Object^ sender);
+ void OnActivated(Windows::ApplicationModel::Core::CoreApplicationView^ applicationView, Windows::ApplicationModel::Activation::IActivatedEventArgs^ args);
+ void OnSuspending(Platform::Object^ sender, Windows::ApplicationModel::SuspendingEventArgs^ args);
+ void OnResuming(Platform::Object^ sender, Platform::Object^ args);
+ void OnWindowClosed(Windows::UI::Core::CoreWindow^ sender, Windows::UI::Core::CoreWindowEventArgs^ args);
+ void OnVisibilityChanged(Windows::UI::Core::CoreWindow^ sender, Windows::UI::Core::VisibilityChangedEventArgs^ args);
+ void OnPointerPressed(Windows::UI::Core::CoreWindow^ sender, Windows::UI::Core::PointerEventArgs^ args);
+ void OnPointerMoved(Windows::UI::Core::CoreWindow^ sender, Windows::UI::Core::PointerEventArgs^ args);
+
+private:
+ CubeRenderer^ m_renderer;
+ bool m_windowClosed;
+ bool m_windowVisible;
+};
+
+ref class Direct3DApplicationSource sealed : Windows::ApplicationModel::Core::IFrameworkViewSource
+{
+public:
+ virtual Windows::ApplicationModel::Core::IFrameworkView^ CreateView();
+};
diff --git a/Tests/VSWinStorePhone/Direct3DApp1/Direct3DApp1_TemporaryKey.pfx b/Tests/VSWinStorePhone/Direct3DApp1/Direct3DApp1_TemporaryKey.pfx
new file mode 100644
index 0000000..1cad999
--- /dev/null
+++ b/Tests/VSWinStorePhone/Direct3DApp1/Direct3DApp1_TemporaryKey.pfx
Binary files differ
diff --git a/Tests/VSWinStorePhone/Direct3DApp1/Direct3DBase.cpp b/Tests/VSWinStorePhone/Direct3DApp1/Direct3DBase.cpp
new file mode 100644
index 0000000..46727b5
--- /dev/null
+++ b/Tests/VSWinStorePhone/Direct3DApp1/Direct3DBase.cpp
@@ -0,0 +1,384 @@
+#include "pch.h"
+#include "Direct3DBase.h"
+
+using namespace DirectX;
+using namespace Microsoft::WRL;
+using namespace Windows::UI::Core;
+using namespace Windows::Foundation;
+using namespace Windows::Graphics::Display;
+
+// Constructor.
+Direct3DBase::Direct3DBase()
+{
+}
+
+// Initialize the Direct3D resources required to run.
+void Direct3DBase::Initialize(CoreWindow^ window)
+{
+ m_window = window;
+
+ CreateDeviceResources();
+ CreateWindowSizeDependentResources();
+}
+
+// Recreate all device resources and set them back to the current state.
+void Direct3DBase::HandleDeviceLost()
+{
+ // Reset these member variables to ensure that UpdateForWindowSizeChange recreates all resources.
+ m_windowBounds.Width = 0;
+ m_windowBounds.Height = 0;
+ m_swapChain = nullptr;
+
+ CreateDeviceResources();
+ UpdateForWindowSizeChange();
+}
+
+// These are the resources that depend on the device.
+void Direct3DBase::CreateDeviceResources()
+{
+ // This flag adds support for surfaces with a different color channel ordering
+ // than the API default. It is required for compatibility with Direct2D.
+ UINT creationFlags = D3D11_CREATE_DEVICE_BGRA_SUPPORT;
+
+#if defined(_DEBUG)
+ // If the project is in a debug build, enable debugging via SDK Layers with this flag.
+ creationFlags |= D3D11_CREATE_DEVICE_DEBUG;
+#endif
+
+ // This array defines the set of DirectX hardware feature levels this app will support.
+ // Note the ordering should be preserved.
+ // Don't forget to declare your application's minimum required feature level in its
+ // description. All applications are assumed to support 9.1 unless otherwise stated.
+ D3D_FEATURE_LEVEL featureLevels[] =
+ {
+ D3D_FEATURE_LEVEL_11_1,
+ D3D_FEATURE_LEVEL_11_0,
+ D3D_FEATURE_LEVEL_10_1,
+ D3D_FEATURE_LEVEL_10_0,
+ D3D_FEATURE_LEVEL_9_3,
+ D3D_FEATURE_LEVEL_9_2,
+ D3D_FEATURE_LEVEL_9_1
+ };
+
+ // Create the Direct3D 11 API device object and a corresponding context.
+ ComPtr<ID3D11Device> device;
+ ComPtr<ID3D11DeviceContext> context;
+ DX::ThrowIfFailed(
+ D3D11CreateDevice(
+ nullptr, // Specify nullptr to use the default adapter.
+ D3D_DRIVER_TYPE_HARDWARE,
+ nullptr,
+ creationFlags, // Set set debug and Direct2D compatibility flags.
+ featureLevels, // List of feature levels this app can support.
+ ARRAYSIZE(featureLevels),
+ D3D11_SDK_VERSION, // Always set this to D3D11_SDK_VERSION for Windows Store apps.
+ &device, // Returns the Direct3D device created.
+ &m_featureLevel, // Returns feature level of device created.
+ &context // Returns the device immediate context.
+ )
+ );
+
+ // Get the Direct3D 11.1 API device and context interfaces.
+ DX::ThrowIfFailed(
+ device.As(&m_d3dDevice)
+ );
+
+ DX::ThrowIfFailed(
+ context.As(&m_d3dContext)
+ );
+}
+
+// Allocate all memory resources that change on a window SizeChanged event.
+void Direct3DBase::CreateWindowSizeDependentResources()
+{
+ // Store the window bounds so the next time we get a SizeChanged event we can
+ // avoid rebuilding everything if the size is identical.
+ m_windowBounds = m_window->Bounds;
+
+ // Calculate the necessary swap chain and render target size in pixels.
+ float windowWidth = ConvertDipsToPixels(m_windowBounds.Width);
+ float windowHeight = ConvertDipsToPixels(m_windowBounds.Height);
+
+ // The width and height of the swap chain must be based on the window's
+ // landscape-oriented width and height. If the window is in a portrait
+ // orientation, the dimensions must be reversed.
+#if WINVER > 0x0602
+ m_orientation = DisplayInformation::GetForCurrentView()->CurrentOrientation;
+#else
+#if PHONE
+ // WP8 doesn't support rotations so always make it landscape
+ m_orientation = DisplayOrientations::Landscape;
+#else
+ m_orientation = DisplayProperties::CurrentOrientation;
+#endif
+#endif
+ bool swapDimensions =
+ m_orientation == DisplayOrientations::Portrait ||
+ m_orientation == DisplayOrientations::PortraitFlipped;
+ m_renderTargetSize.Width = swapDimensions ? windowHeight : windowWidth;
+ m_renderTargetSize.Height = swapDimensions ? windowWidth : windowHeight;
+
+ if(m_swapChain != nullptr)
+ {
+ // If the swap chain already exists, resize it.
+ DX::ThrowIfFailed(
+ m_swapChain->ResizeBuffers(
+ 2, // Double-buffered swap chain.
+ static_cast<UINT>(m_renderTargetSize.Width),
+ static_cast<UINT>(m_renderTargetSize.Height),
+ DXGI_FORMAT_B8G8R8A8_UNORM,
+ 0
+ )
+ );
+ }
+ else
+ {
+ // Otherwise, create a new one using the same adapter as the existing Direct3D device.
+ DXGI_SWAP_CHAIN_DESC1 swapChainDesc = {0};
+ swapChainDesc.Width = static_cast<UINT>(m_renderTargetSize.Width); // Match the size of the window.
+ swapChainDesc.Height = static_cast<UINT>(m_renderTargetSize.Height);
+ swapChainDesc.Format = DXGI_FORMAT_B8G8R8A8_UNORM; // This is the most common swap chain format.
+ swapChainDesc.Stereo = false;
+ swapChainDesc.SampleDesc.Count = 1; // Don't use multi-sampling.
+ swapChainDesc.SampleDesc.Quality = 0;
+ swapChainDesc.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT;
+#if PHONE && WINVER <= 0x0602
+ swapChainDesc.BufferCount = 1; // Use double-buffering to minimize latency.
+ swapChainDesc.Scaling = DXGI_SCALING_STRETCH; // On phone, only stretch and aspect-ratio stretch scaling are allowed.
+ swapChainDesc.SwapEffect = DXGI_SWAP_EFFECT_DISCARD; // On phone, no swap effects are supported.
+#else
+ swapChainDesc.BufferCount = 2; // Use double-buffering to minimize latency.
+ swapChainDesc.Scaling = DXGI_SCALING_NONE;
+ swapChainDesc.SwapEffect = DXGI_SWAP_EFFECT_FLIP_SEQUENTIAL; // All Windows Store apps must use this SwapEffect.
+#endif
+ swapChainDesc.Flags = 0;
+
+ ComPtr<IDXGIDevice1> dxgiDevice;
+ DX::ThrowIfFailed(
+ m_d3dDevice.As(&dxgiDevice)
+ );
+
+ ComPtr<IDXGIAdapter> dxgiAdapter;
+ DX::ThrowIfFailed(
+ dxgiDevice->GetAdapter(&dxgiAdapter)
+ );
+
+ ComPtr<IDXGIFactory2> dxgiFactory;
+ DX::ThrowIfFailed(
+ dxgiAdapter->GetParent(
+ __uuidof(IDXGIFactory2),
+ &dxgiFactory
+ )
+ );
+
+ Windows::UI::Core::CoreWindow^ window = m_window.Get();
+ DX::ThrowIfFailed(
+ dxgiFactory->CreateSwapChainForCoreWindow(
+ m_d3dDevice.Get(),
+ reinterpret_cast<IUnknown*>(window),
+ &swapChainDesc,
+ nullptr, // Allow on all displays.
+ &m_swapChain
+ )
+ );
+
+ // Ensure that DXGI does not queue more than one frame at a time. This both reduces latency and
+ // ensures that the application will only render after each VSync, minimizing power consumption.
+ DX::ThrowIfFailed(
+ dxgiDevice->SetMaximumFrameLatency(1)
+ );
+ }
+
+ // Set the proper orientation for the swap chain, and generate the
+ // 3D matrix transformation for rendering to the rotated swap chain.
+ DXGI_MODE_ROTATION rotation = DXGI_MODE_ROTATION_UNSPECIFIED;
+ switch (m_orientation)
+ {
+ case DisplayOrientations::Landscape:
+ rotation = DXGI_MODE_ROTATION_IDENTITY;
+ m_orientationTransform3D = XMFLOAT4X4( // 0-degree Z-rotation
+ 1.0f, 0.0f, 0.0f, 0.0f,
+ 0.0f, 1.0f, 0.0f, 0.0f,
+ 0.0f, 0.0f, 1.0f, 0.0f,
+ 0.0f, 0.0f, 0.0f, 1.0f
+ );
+ break;
+
+ case DisplayOrientations::Portrait:
+ rotation = DXGI_MODE_ROTATION_ROTATE270;
+ m_orientationTransform3D = XMFLOAT4X4( // 90-degree Z-rotation
+ 0.0f, 1.0f, 0.0f, 0.0f,
+ -1.0f, 0.0f, 0.0f, 0.0f,
+ 0.0f, 0.0f, 1.0f, 0.0f,
+ 0.0f, 0.0f, 0.0f, 1.0f
+ );
+ break;
+
+ case DisplayOrientations::LandscapeFlipped:
+ rotation = DXGI_MODE_ROTATION_ROTATE180;
+ m_orientationTransform3D = XMFLOAT4X4( // 180-degree Z-rotation
+ -1.0f, 0.0f, 0.0f, 0.0f,
+ 0.0f, -1.0f, 0.0f, 0.0f,
+ 0.0f, 0.0f, 1.0f, 0.0f,
+ 0.0f, 0.0f, 0.0f, 1.0f
+ );
+ break;
+
+ case DisplayOrientations::PortraitFlipped:
+ rotation = DXGI_MODE_ROTATION_ROTATE90;
+ m_orientationTransform3D = XMFLOAT4X4( // 270-degree Z-rotation
+ 0.0f, -1.0f, 0.0f, 0.0f,
+ 1.0f, 0.0f, 0.0f, 0.0f,
+ 0.0f, 0.0f, 1.0f, 0.0f,
+ 0.0f, 0.0f, 0.0f, 1.0f
+ );
+ break;
+
+ default:
+ throw ref new Platform::FailureException();
+ }
+
+#if !PHONE || WINVER > 0x0602
+ DX::ThrowIfFailed(
+ m_swapChain->SetRotation(rotation)
+ );
+#endif // !PHONE
+
+ // Create a render target view of the swap chain back buffer.
+ ComPtr<ID3D11Texture2D> backBuffer;
+ DX::ThrowIfFailed(
+ m_swapChain->GetBuffer(
+ 0,
+ __uuidof(ID3D11Texture2D),
+ &backBuffer
+ )
+ );
+
+ DX::ThrowIfFailed(
+ m_d3dDevice->CreateRenderTargetView(
+ backBuffer.Get(),
+ nullptr,
+ &m_renderTargetView
+ )
+ );
+
+ // Create a depth stencil view.
+ CD3D11_TEXTURE2D_DESC depthStencilDesc(
+ DXGI_FORMAT_D24_UNORM_S8_UINT,
+ static_cast<UINT>(m_renderTargetSize.Width),
+ static_cast<UINT>(m_renderTargetSize.Height),
+ 1,
+ 1,
+ D3D11_BIND_DEPTH_STENCIL
+ );
+
+ ComPtr<ID3D11Texture2D> depthStencil;
+ DX::ThrowIfFailed(
+ m_d3dDevice->CreateTexture2D(
+ &depthStencilDesc,
+ nullptr,
+ &depthStencil
+ )
+ );
+
+ CD3D11_DEPTH_STENCIL_VIEW_DESC depthStencilViewDesc(D3D11_DSV_DIMENSION_TEXTURE2D);
+ DX::ThrowIfFailed(
+ m_d3dDevice->CreateDepthStencilView(
+ depthStencil.Get(),
+ &depthStencilViewDesc,
+ &m_depthStencilView
+ )
+ );
+
+ // Set the rendering viewport to target the entire window.
+ CD3D11_VIEWPORT viewport(
+ 0.0f,
+ 0.0f,
+ m_renderTargetSize.Width,
+ m_renderTargetSize.Height
+ );
+
+ m_d3dContext->RSSetViewports(1, &viewport);
+}
+
+// This method is called in the event handler for the SizeChanged event.
+void Direct3DBase::UpdateForWindowSizeChange()
+{
+ if (m_window->Bounds.Width != m_windowBounds.Width ||
+ m_window->Bounds.Height != m_windowBounds.Height ||
+#if WINVER > 0x0602
+ m_orientation != DisplayInformation::GetForCurrentView()->CurrentOrientation)
+#else
+ m_orientation != DisplayProperties::CurrentOrientation)
+#endif
+ {
+ ID3D11RenderTargetView* nullViews[] = {nullptr};
+ m_d3dContext->OMSetRenderTargets(ARRAYSIZE(nullViews), nullViews, nullptr);
+ m_renderTargetView = nullptr;
+ m_depthStencilView = nullptr;
+ m_d3dContext->Flush();
+ CreateWindowSizeDependentResources();
+ }
+}
+
+void Direct3DBase::ReleaseResourcesForSuspending()
+{
+ // Phone applications operate in a memory-constrained environment, so when entering
+ // the background it is a good idea to free memory-intensive objects that will be
+ // easy to restore upon reactivation. The swapchain and backbuffer are good candidates
+ // here, as they consume a large amount of memory and can be reinitialized quickly.
+ m_swapChain = nullptr;
+ m_renderTargetView = nullptr;
+ m_depthStencilView = nullptr;
+}
+
+// Method to deliver the final image to the display.
+void Direct3DBase::Present()
+{
+ // The first argument instructs DXGI to block until VSync, putting the application
+ // to sleep until the next VSync. This ensures we don't waste any cycles rendering
+ // frames that will never be displayed to the screen.
+#if PHONE && WINVER <= 0x0602
+ HRESULT hr = m_swapChain->Present(1, 0);
+#else
+ // The application may optionally specify "dirty" or "scroll"
+ // rects to improve efficiency in certain scenarios.
+ DXGI_PRESENT_PARAMETERS parameters = { 0 };
+ parameters.DirtyRectsCount = 0;
+ parameters.pDirtyRects = nullptr;
+ parameters.pScrollRect = nullptr;
+ parameters.pScrollOffset = nullptr;
+
+ HRESULT hr = m_swapChain->Present1(1, 0 , &parameters);
+#endif
+
+ // Discard the contents of the render target.
+ // This is a valid operation only when the existing contents will be entirely
+ // overwritten. If dirty or scroll rects are used, this call should be removed.
+ m_d3dContext->DiscardView(m_renderTargetView.Get());
+
+ // Discard the contents of the depth stencil.
+ m_d3dContext->DiscardView(m_depthStencilView.Get());
+
+ // If the device was removed either by a disconnect or a driver upgrade, we
+ // must recreate all device resources.
+ if (hr == DXGI_ERROR_DEVICE_REMOVED)
+ {
+ HandleDeviceLost();
+ }
+ else
+ {
+ DX::ThrowIfFailed(hr);
+ }
+}
+
+// Method to convert a length in device-independent pixels (DIPs) to a length in physical pixels.
+float Direct3DBase::ConvertDipsToPixels(float dips)
+{
+ static const float dipsPerInch = 96.0f;
+#if WINVER > 0x0602
+ return floor(dips * DisplayInformation::GetForCurrentView()->LogicalDpi / dipsPerInch + 0.5f); // Round to nearest integer.
+#else
+ return floor(dips * DisplayProperties::LogicalDpi / dipsPerInch + 0.5f); // Round to nearest integer.
+#endif
+}
diff --git a/Tests/VSWinStorePhone/Direct3DApp1/Direct3DBase.h b/Tests/VSWinStorePhone/Direct3DApp1/Direct3DBase.h
new file mode 100644
index 0000000..bba9f16
--- /dev/null
+++ b/Tests/VSWinStorePhone/Direct3DApp1/Direct3DBase.h
@@ -0,0 +1,39 @@
+#pragma once
+
+#include "DirectXHelper.h"
+
+// Helper class that initializes DirectX APIs for 3D rendering.
+ref class Direct3DBase abstract
+{
+internal:
+ Direct3DBase();
+
+public:
+ virtual void Initialize(Windows::UI::Core::CoreWindow^ window);
+ virtual void HandleDeviceLost();
+ virtual void CreateDeviceResources();
+ virtual void CreateWindowSizeDependentResources();
+ virtual void UpdateForWindowSizeChange();
+ virtual void ReleaseResourcesForSuspending();
+ virtual void Render() = 0;
+ virtual void Present();
+ virtual float ConvertDipsToPixels(float dips);
+
+protected private:
+ // Direct3D Objects.
+ Microsoft::WRL::ComPtr<ID3D11Device1> m_d3dDevice;
+ Microsoft::WRL::ComPtr<ID3D11DeviceContext1> m_d3dContext;
+ Microsoft::WRL::ComPtr<IDXGISwapChain1> m_swapChain;
+ Microsoft::WRL::ComPtr<ID3D11RenderTargetView> m_renderTargetView;
+ Microsoft::WRL::ComPtr<ID3D11DepthStencilView> m_depthStencilView;
+
+ // Cached renderer properties.
+ D3D_FEATURE_LEVEL m_featureLevel;
+ Windows::Foundation::Size m_renderTargetSize;
+ Windows::Foundation::Rect m_windowBounds;
+ Platform::Agile<Windows::UI::Core::CoreWindow> m_window;
+ Windows::Graphics::Display::DisplayOrientations m_orientation;
+
+ // Transform used for display orientation.
+ DirectX::XMFLOAT4X4 m_orientationTransform3D;
+};
diff --git a/Tests/VSWinStorePhone/Direct3DApp1/DirectXHelper.h b/Tests/VSWinStorePhone/Direct3DApp1/DirectXHelper.h
new file mode 100644
index 0000000..d411a9b
--- /dev/null
+++ b/Tests/VSWinStorePhone/Direct3DApp1/DirectXHelper.h
@@ -0,0 +1,45 @@
+#pragma once
+
+#include <wrl/client.h>
+#include <ppl.h>
+#include <ppltasks.h>
+
+namespace DX
+{
+ inline void ThrowIfFailed(HRESULT hr)
+ {
+ if (FAILED(hr))
+ {
+ // Set a breakpoint on this line to catch Win32 API errors.
+ throw Platform::Exception::CreateException(hr);
+ }
+ }
+
+ // Function that reads from a binary file asynchronously.
+ inline Concurrency::task<Platform::Array<byte>^> ReadDataAsync(Platform::String^ filename)
+ {
+ using namespace Windows::Storage;
+ using namespace Concurrency;
+
+ auto folder = Windows::ApplicationModel::Package::Current->InstalledLocation;
+
+ return create_task(folder->GetFileAsync(filename)).then([] (StorageFile^ file)
+ {
+#if !PHONE
+ return FileIO::ReadBufferAsync(file);
+#else
+ return file->OpenReadAsync();
+ }).then([](Streams::IRandomAccessStreamWithContentType^ stream)
+ {
+ unsigned int bufferSize = static_cast<unsigned int>(stream->Size);
+ auto fileBuffer = ref new Streams::Buffer(bufferSize);
+ return stream->ReadAsync(fileBuffer, bufferSize, Streams::InputStreamOptions::None);
+#endif
+ }).then([] (Streams::IBuffer^ fileBuffer) -> Platform::Array<byte>^
+ {
+ auto fileData = ref new Platform::Array<byte>(fileBuffer->Length);
+ Streams::DataReader::FromBuffer(fileBuffer)->ReadBytes(fileData);
+ return fileData;
+ });
+ }
+}
diff --git a/Tests/VSWinStorePhone/Direct3DApp1/SimplePixelShader.cso b/Tests/VSWinStorePhone/Direct3DApp1/SimplePixelShader.cso
new file mode 100644
index 0000000..56f9c17
--- /dev/null
+++ b/Tests/VSWinStorePhone/Direct3DApp1/SimplePixelShader.cso
Binary files differ
diff --git a/Tests/VSWinStorePhone/Direct3DApp1/SimplePixelShader.hlsl b/Tests/VSWinStorePhone/Direct3DApp1/SimplePixelShader.hlsl
new file mode 100644
index 0000000..d61e2c8
--- /dev/null
+++ b/Tests/VSWinStorePhone/Direct3DApp1/SimplePixelShader.hlsl
@@ -0,0 +1,10 @@
+struct PixelShaderInput
+{
+ float4 pos : SV_POSITION;
+ float3 color : COLOR0;
+};
+
+float4 main(PixelShaderInput input) : SV_TARGET
+{
+ return float4(input.color,1.0f);
+}
diff --git a/Tests/VSWinStorePhone/Direct3DApp1/SimpleVertexShader.cso b/Tests/VSWinStorePhone/Direct3DApp1/SimpleVertexShader.cso
new file mode 100644
index 0000000..ea80258
--- /dev/null
+++ b/Tests/VSWinStorePhone/Direct3DApp1/SimpleVertexShader.cso
Binary files differ
diff --git a/Tests/VSWinStorePhone/Direct3DApp1/SimpleVertexShader.hlsl b/Tests/VSWinStorePhone/Direct3DApp1/SimpleVertexShader.hlsl
new file mode 100644
index 0000000..65d60e5
--- /dev/null
+++ b/Tests/VSWinStorePhone/Direct3DApp1/SimpleVertexShader.hlsl
@@ -0,0 +1,35 @@
+cbuffer ModelViewProjectionConstantBuffer : register(b0)
+{
+ matrix model;
+ matrix view;
+ matrix projection;
+};
+
+struct VertexShaderInput
+{
+ float3 pos : POSITION;
+ float3 color : COLOR0;
+};
+
+struct VertexShaderOutput
+{
+ float4 pos : SV_POSITION;
+ float3 color : COLOR0;
+};
+
+VertexShaderOutput main(VertexShaderInput input)
+{
+ VertexShaderOutput output;
+ float4 pos = float4(input.pos, 1.0f);
+
+ // Transform the vertex position into projected space.
+ pos = mul(pos, model);
+ pos = mul(pos, view);
+ pos = mul(pos, projection);
+ output.pos = pos;
+
+ // Pass through the color without modification.
+ output.color = input.color;
+
+ return output;
+}
diff --git a/Tests/VSWinStorePhone/Direct3DApp1/pch.cpp b/Tests/VSWinStorePhone/Direct3DApp1/pch.cpp
new file mode 100644