• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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