Home | History | Annotate | Download | only in win
      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::VideoFrame& 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