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 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 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 44 D3dRenderer::~D3dRenderer() { Destroy(); } 45 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 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 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 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 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 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