1 /*
2 * Copyright (c) 2013 The WebRTC project authors. All Rights Reserved.
3 *
4 * Use of this source code is governed by a BSD-style license
5 * that can be found in the LICENSE file in the root of the source
6 * tree. An additional intellectual property rights grant can be found
7 * in the file PATENTS. All contributing project authors may
8 * be found in the AUTHORS file in the root of the source tree.
9 */
10 #include "webrtc/test/win/d3d_renderer.h"
11
12 #include "webrtc/common_video/libyuv/include/webrtc_libyuv.h"
13
14 namespace webrtc {
15 namespace test {
16
17 #define D3DFVF_CUSTOMVERTEX (D3DFVF_XYZ|D3DFVF_TEX1)
18
19 struct D3dCustomVertex {
20 float x, y, z;
21 float u, v;
22 };
23
24 const char kD3DClassName[] = "d3d_renderer";
25
CreatePlatformRenderer(const char * window_title,size_t width,size_t height)26 VideoRenderer* VideoRenderer::CreatePlatformRenderer(const char* window_title,
27 size_t width,
28 size_t height) {
29 return D3dRenderer::Create(window_title, width, height);
30 }
31
D3dRenderer(size_t width,size_t height)32 D3dRenderer::D3dRenderer(size_t width, size_t height)
33 : width_(width),
34 height_(height),
35 hwnd_(NULL),
36 d3d_(NULL),
37 d3d_device_(NULL),
38 texture_(NULL),
39 vertex_buffer_(NULL) {
40 assert(width > 0);
41 assert(height > 0);
42 }
43
~D3dRenderer()44 D3dRenderer::~D3dRenderer() { Destroy(); }
45
WindowProc(HWND hwnd,UINT msg,WPARAM wparam,LPARAM lparam)46 LRESULT WINAPI D3dRenderer::WindowProc(HWND hwnd, UINT msg, WPARAM wparam,
47 LPARAM lparam) {
48 if (msg == WM_DESTROY || (msg == WM_CHAR && wparam == VK_RETURN)) {
49 PostQuitMessage(0);
50 return 0;
51 }
52
53 return DefWindowProcA(hwnd, msg, wparam, lparam);
54 }
55
Destroy()56 void D3dRenderer::Destroy() {
57 texture_ = NULL;
58 vertex_buffer_ = NULL;
59 d3d_device_ = NULL;
60 d3d_ = NULL;
61
62 if (hwnd_ != NULL) {
63 DestroyWindow(hwnd_);
64 assert(!IsWindow(hwnd_));
65 hwnd_ = NULL;
66 }
67 }
68
Init(const char * window_title)69 bool D3dRenderer::Init(const char* window_title) {
70 hwnd_ = CreateWindowA(kD3DClassName,
71 window_title,
72 WS_OVERLAPPEDWINDOW,
73 0,
74 0,
75 static_cast<int>(width_),
76 static_cast<int>(height_),
77 NULL,
78 NULL,
79 NULL,
80 NULL);
81
82 if (hwnd_ == NULL) {
83 Destroy();
84 return false;
85 }
86
87 d3d_ = Direct3DCreate9(D3D_SDK_VERSION);
88 if (d3d_ == NULL) {
89 Destroy();
90 return false;
91 }
92
93 D3DPRESENT_PARAMETERS d3d_params = {};
94
95 d3d_params.Windowed = TRUE;
96 d3d_params.SwapEffect = D3DSWAPEFFECT_COPY;
97
98 IDirect3DDevice9* d3d_device;
99 if (d3d_->CreateDevice(D3DADAPTER_DEFAULT,
100 D3DDEVTYPE_HAL,
101 hwnd_,
102 D3DCREATE_SOFTWARE_VERTEXPROCESSING,
103 &d3d_params,
104 &d3d_device) != D3D_OK) {
105 Destroy();
106 return false;
107 }
108 d3d_device_ = d3d_device;
109 d3d_device->Release();
110
111 IDirect3DVertexBuffer9* vertex_buffer;
112 const int kRectVertices = 4;
113 if (d3d_device_->CreateVertexBuffer(kRectVertices * sizeof(D3dCustomVertex),
114 0,
115 D3DFVF_CUSTOMVERTEX,
116 D3DPOOL_MANAGED,
117 &vertex_buffer,
118 NULL) != D3D_OK) {
119 Destroy();
120 return false;
121 }
122 vertex_buffer_ = vertex_buffer;
123 vertex_buffer->Release();
124
125 d3d_device_->SetRenderState(D3DRS_CULLMODE, D3DCULL_NONE);
126 d3d_device_->SetRenderState(D3DRS_LIGHTING, FALSE);
127 Resize(width_, height_);
128
129 ShowWindow(hwnd_, SW_SHOWNOACTIVATE);
130 d3d_device_->Present(NULL, NULL, NULL, NULL);
131
132 return true;
133 }
134
Create(const char * window_title,size_t width,size_t height)135 D3dRenderer* D3dRenderer::Create(const char* window_title,
136 size_t width,
137 size_t height) {
138 static ATOM wc_atom = 0;
139 if (wc_atom == 0) {
140 WNDCLASSA wc = {};
141
142 wc.style = CS_HREDRAW | CS_VREDRAW;
143 wc.lpfnWndProc = WindowProc;
144 wc.hCursor = LoadCursor(NULL, IDC_ARROW);
145 wc.hbrBackground = reinterpret_cast<HBRUSH>(COLOR_WINDOW);
146 wc.lpszClassName = kD3DClassName;
147
148 wc_atom = RegisterClassA(&wc);
149 if (wc_atom == 0)
150 return false;
151 }
152
153 D3dRenderer* d3d_renderer = new D3dRenderer(width, height);
154 if (!d3d_renderer->Init(window_title)) {
155 delete d3d_renderer;
156 return NULL;
157 }
158
159 return d3d_renderer;
160 }
161
Resize(size_t width,size_t height)162 void D3dRenderer::Resize(size_t width, size_t height) {
163 width_ = width;
164 height_ = height;
165 IDirect3DTexture9* texture;
166
167 d3d_device_->CreateTexture(static_cast<UINT>(width_),
168 static_cast<UINT>(height_),
169 1,
170 0,
171 D3DFMT_A8R8G8B8,
172 D3DPOOL_MANAGED,
173 &texture,
174 NULL);
175 texture_ = texture;
176 texture->Release();
177
178 // Vertices for the video frame to be rendered to.
179 static const D3dCustomVertex rect[] = {
180 {-1.0f, -1.0f, 0.0f, 0.0f, 1.0f},
181 {-1.0f, 1.0f, 0.0f, 0.0f, 0.0f},
182 {1.0f, -1.0f, 0.0f, 1.0f, 1.0f},
183 {1.0f, 1.0f, 0.0f, 1.0f, 0.0f},
184 };
185
186 void* buf_data;
187 if (vertex_buffer_->Lock(0, 0, &buf_data, 0) != D3D_OK)
188 return;
189
190 memcpy(buf_data, &rect, sizeof(rect));
191 vertex_buffer_->Unlock();
192 }
193
RenderFrame(const webrtc::I420VideoFrame & frame,int)194 void D3dRenderer::RenderFrame(const webrtc::I420VideoFrame& frame,
195 int /*render_delay_ms*/) {
196 if (static_cast<size_t>(frame.width()) != width_ ||
197 static_cast<size_t>(frame.height()) != height_) {
198 Resize(static_cast<size_t>(frame.width()),
199 static_cast<size_t>(frame.height()));
200 }
201
202 D3DLOCKED_RECT lock_rect;
203 if (texture_->LockRect(0, &lock_rect, NULL, 0) != D3D_OK)
204 return;
205
206 ConvertFromI420(frame, kARGB, 0, static_cast<uint8_t*>(lock_rect.pBits));
207 texture_->UnlockRect(0);
208
209 d3d_device_->BeginScene();
210 d3d_device_->SetFVF(D3DFVF_CUSTOMVERTEX);
211 d3d_device_->SetStreamSource(0, vertex_buffer_, 0, sizeof(D3dCustomVertex));
212 d3d_device_->SetTexture(0, texture_);
213 d3d_device_->DrawPrimitive(D3DPT_TRIANGLESTRIP, 0, 2);
214 d3d_device_->EndScene();
215
216 d3d_device_->Present(NULL, NULL, NULL, NULL);
217 }
218 } // namespace test
219 } // namespace webrtc
220