OLD | NEW |
| (Empty) |
1 // Copyright (c) 2011 The Chromium Authors. All rights reserved. | |
2 // Use of this source code is governed by a BSD-style license that can be | |
3 // found in the LICENSE file. | |
4 | |
5 #include "ui/gfx/compositor/compositor.h" | |
6 | |
7 #include <algorithm> | |
8 #include <d3dx10.h> | |
9 #include <vector> | |
10 | |
11 #include "base/compiler_specific.h" | |
12 #include "base/logging.h" | |
13 #include "base/stl_util.h" | |
14 #include "base/string_piece.h" | |
15 #include "base/win/scoped_comptr.h" | |
16 #include "grit/gfx_resources.h" | |
17 #include "third_party/skia/include/core/SkCanvas.h" | |
18 #include "ui/base/resource/resource_bundle.h" | |
19 #include "ui/gfx/canvas_skia.h" | |
20 #include "ui/gfx/rect.h" | |
21 #include "ui/gfx/transform.h" | |
22 | |
23 // TODO(sky): this is a hack, figure out real error handling. | |
24 #define RETURN_IF_FAILED(error) \ | |
25 if (error != S_OK) { \ | |
26 this->Errored(error); \ | |
27 VLOG(1) << "D3D failed" << error; \ | |
28 return; \ | |
29 } | |
30 | |
31 using base::win::ScopedComPtr; | |
32 | |
33 namespace ui { | |
34 | |
35 namespace { | |
36 | |
37 class CompositorWin; | |
38 | |
39 // Vertex structure used by the compositor. | |
40 struct Vertex { | |
41 D3DXVECTOR3 position; | |
42 D3DXVECTOR2 texture_offset; | |
43 }; | |
44 | |
45 // D3D 10 Texture implementation. Creates a quad representing the view and | |
46 // a texture with the bitmap data. The quad has an origin of 0,0,0 with a size | |
47 // matching that of |SetCanvas|. | |
48 class ViewTexture : public Texture { | |
49 public: | |
50 ViewTexture(CompositorWin* compositor, | |
51 ID3D10Device* device, | |
52 ID3D10Effect* effect); | |
53 | |
54 // Texture: | |
55 virtual void SetCanvas(const SkCanvas& canvas, | |
56 const gfx::Point& origin, | |
57 const gfx::Size& overall_size) OVERRIDE; | |
58 virtual void Draw(const ui::TextureDrawParams& params, | |
59 const gfx::Rect& clip_bounds_in_texture) OVERRIDE; | |
60 | |
61 private: | |
62 ~ViewTexture(); | |
63 | |
64 void Errored(HRESULT result); | |
65 | |
66 void ConvertBitmapToD3DData(const SkBitmap& bitmap, | |
67 scoped_array<uint32>* converted_data); | |
68 | |
69 // Creates vertex buffer for specified region | |
70 void CreateVertexBufferForRegion(const gfx::Rect& bounds); | |
71 | |
72 scoped_refptr<CompositorWin> compositor_; | |
73 | |
74 // Size of the corresponding View. | |
75 gfx::Size view_size_; | |
76 | |
77 ScopedComPtr<ID3D10Device> device_; | |
78 ScopedComPtr<ID3D10Effect, NULL> effect_; | |
79 ScopedComPtr<ID3D10Texture2D> texture_; | |
80 ScopedComPtr<ID3D10ShaderResourceView> shader_view_; | |
81 ScopedComPtr<ID3D10Buffer> vertex_buffer_; | |
82 | |
83 DISALLOW_COPY_AND_ASSIGN(ViewTexture); | |
84 }; | |
85 | |
86 // D3D 10 Compositor implementation. | |
87 class CompositorWin : public Compositor { | |
88 public: | |
89 CompositorWin(CompositorDelegate* delegate, | |
90 gfx::AcceleratedWidget widget, | |
91 const gfx::Size& size); | |
92 | |
93 void Init(); | |
94 | |
95 // Invoked to update the perspective needed by this texture. |transform| is | |
96 // the transform for the texture, and |size| the size of the texture. | |
97 void UpdatePerspective(const ui::Transform& transform, | |
98 const gfx::Size& view_size); | |
99 | |
100 // Returns the index buffer used for drawing a texture. | |
101 ID3D10Buffer* GetTextureIndexBuffer(); | |
102 | |
103 // Compositor: | |
104 virtual Texture* CreateTexture() OVERRIDE; | |
105 | |
106 virtual void Blur(const gfx::Rect& bounds) OVERRIDE; | |
107 | |
108 virtual bool ReadPixels(SkBitmap* bitmap, const gfx::Rect& bounds) OVERRIDE; | |
109 | |
110 protected: | |
111 virtual void OnNotifyStart(bool clear) OVERRIDE; | |
112 virtual void OnNotifyEnd() OVERRIDE; | |
113 virtual void OnWidgetSizeChanged() OVERRIDE; | |
114 | |
115 private: | |
116 enum Direction { | |
117 HORIZONTAL, | |
118 VERTICAL | |
119 }; | |
120 | |
121 ~CompositorWin(); | |
122 | |
123 void Errored(HRESULT error_code); | |
124 | |
125 void CreateDevice(); | |
126 | |
127 void LoadEffects(); | |
128 | |
129 void InitVertexLayout(); | |
130 | |
131 // Updates the kernel used for blurring. Size is the size of the texture | |
132 // being drawn to along the appropriate axis. | |
133 void UpdateBlurKernel(Direction direction, int size); | |
134 | |
135 // Creates a texture, render target view and shader. | |
136 void CreateTexture(const gfx::Size& size, | |
137 ID3D10Texture2D** texture, | |
138 ID3D10RenderTargetView** render_target_view, | |
139 ID3D10ShaderResourceView** shader_resource_view); | |
140 | |
141 // Creates |vertex_buffer_|. | |
142 void CreateVertexBuffer(); | |
143 | |
144 // Creates |index_buffer_|. | |
145 void CreateIndexBuffer(); | |
146 | |
147 // Creates a vertex buffer for the specified region. The caller owns the | |
148 // return value. | |
149 ID3D10Buffer* CreateVertexBufferForRegion(const gfx::Rect& bounds); | |
150 | |
151 gfx::AcceleratedWidget host_; | |
152 | |
153 ScopedComPtr<ID3D10Device> device_; | |
154 ScopedComPtr<IDXGISwapChain> swap_chain_; | |
155 ScopedComPtr<ID3D10RenderTargetView> dest_render_target_view_; | |
156 ScopedComPtr<ID3D10Texture2D> depth_stencil_buffer_; | |
157 ScopedComPtr<ID3D10DepthStencilView> depth_stencil_view_; | |
158 ScopedComPtr<ID3D10Effect, NULL> fx_; | |
159 ID3D10EffectTechnique* technique_; | |
160 | |
161 // Layout for Vertex. | |
162 ScopedComPtr<ID3D10InputLayout> vertex_layout_; | |
163 | |
164 // Identity vertext buffer. Used when copying from main back to dest. | |
165 ScopedComPtr<ID3D10Buffer> vertex_buffer_; | |
166 | |
167 // Index buffer used for drawing a rectangle. | |
168 ScopedComPtr<ID3D10Buffer> index_buffer_; | |
169 | |
170 // Used for bluring. | |
171 ScopedComPtr<ID3D10Effect, NULL> blur_fx_; | |
172 ID3D10EffectTechnique* blur_technique_; | |
173 | |
174 // All rendering is done to the main_texture. Effects (such as bloom) render | |
175 // into the blur texture, and are then copied back to the main texture. When | |
176 // rendering is done |main_texture_| is drawn back to | |
177 // |dest_render_target_view_|. | |
178 ScopedComPtr<ID3D10Texture2D> main_texture_; | |
179 ScopedComPtr<ID3D10RenderTargetView> main_render_target_view_; | |
180 ScopedComPtr<ID3D10ShaderResourceView> main_texture_shader_view_; | |
181 | |
182 ScopedComPtr<ID3D10Texture2D> blur_texture_; | |
183 ScopedComPtr<ID3D10RenderTargetView> blur_render_target_view_; | |
184 ScopedComPtr<ID3D10ShaderResourceView> blur_texture_shader_view_; | |
185 | |
186 DISALLOW_COPY_AND_ASSIGN(CompositorWin); | |
187 }; | |
188 | |
189 ViewTexture::ViewTexture(CompositorWin* compositor, | |
190 ID3D10Device* device, | |
191 ID3D10Effect* effect) | |
192 : compositor_(compositor), | |
193 device_(device), | |
194 effect_(effect) { | |
195 } | |
196 | |
197 ViewTexture::~ViewTexture() { | |
198 } | |
199 | |
200 void ViewTexture::SetCanvas(const SkCanvas& canvas, | |
201 const gfx::Point& origin, | |
202 const gfx::Size& overall_size) { | |
203 view_size_ = overall_size; | |
204 | |
205 scoped_array<uint32> converted_data; | |
206 const SkBitmap& bitmap = canvas.getDevice()->accessBitmap(false); | |
207 ConvertBitmapToD3DData(bitmap, &converted_data); | |
208 if (gfx::Size(bitmap.width(), bitmap.height()) == overall_size) { | |
209 shader_view_.Release(); | |
210 texture_.Release(); | |
211 | |
212 D3D10_TEXTURE2D_DESC texture_desc; | |
213 texture_desc.Width = bitmap.width(); | |
214 texture_desc.Height = bitmap.height(); | |
215 texture_desc.MipLevels = 1; | |
216 texture_desc.ArraySize = 1; | |
217 texture_desc.Format = DXGI_FORMAT_R8G8B8A8_UNORM; | |
218 texture_desc.SampleDesc.Count = 1; | |
219 texture_desc.SampleDesc.Quality = 0; | |
220 texture_desc.Usage = D3D10_USAGE_DEFAULT; | |
221 texture_desc.BindFlags = D3D10_BIND_SHADER_RESOURCE; | |
222 texture_desc.CPUAccessFlags = 0; | |
223 texture_desc.MiscFlags = 0; | |
224 RETURN_IF_FAILED(device_->CreateTexture2D(&texture_desc, | |
225 NULL, texture_.Receive())); | |
226 RETURN_IF_FAILED( | |
227 device_->CreateShaderResourceView(texture_.get(), NULL, | |
228 shader_view_.Receive())); | |
229 } | |
230 DCHECK(texture_.get()); | |
231 D3D10_BOX dst_box = { origin.x(), origin.y(), 0, | |
232 origin.x() + bitmap.width(), | |
233 origin.y() + bitmap.height(), 1 }; | |
234 device_->UpdateSubresource(texture_.get(), 0, &dst_box, | |
235 converted_data.get(), bitmap.width() * 4, 0); | |
236 } | |
237 | |
238 void ViewTexture::Draw(const ui::TextureDrawParams& params, | |
239 const gfx::Rect& clip_bounds) { | |
240 if (params.vertically_flipped) | |
241 NOTIMPLEMENTED(); | |
242 | |
243 compositor_->UpdatePerspective(params.transform, view_size_); | |
244 | |
245 // Make texture active. | |
246 RETURN_IF_FAILED( | |
247 effect_->GetVariableByName("textureMap")->AsShaderResource()-> | |
248 SetResource(shader_view_.get())); | |
249 | |
250 RETURN_IF_FAILED(effect_->GetVariableByName("alpha")->AsScalar()->SetFloat( | |
251 params.opacity)); | |
252 | |
253 ID3D10EffectTechnique* technique = effect_->GetTechniqueByName("ViewTech"); | |
254 DCHECK(technique); | |
255 D3D10_TECHNIQUE_DESC tech_desc; | |
256 technique->GetDesc(&tech_desc); | |
257 for(UINT p = 0; p < tech_desc.Passes; ++p) | |
258 technique->GetPassByIndex(p)->Apply(0); | |
259 | |
260 UINT stride = sizeof(Vertex); | |
261 UINT offset = 0; | |
262 CreateVertexBufferForRegion(clip_bounds); | |
263 ID3D10Buffer* vertex_buffer = vertex_buffer_.get(); | |
264 device_->IASetVertexBuffers(0, 1, &vertex_buffer, &stride, &offset); | |
265 device_->IASetIndexBuffer(compositor_->GetTextureIndexBuffer(), | |
266 DXGI_FORMAT_R32_UINT, 0); | |
267 device_->DrawIndexed(6, 0, 0); | |
268 } | |
269 | |
270 void ViewTexture::Errored(HRESULT result) { | |
271 // TODO: figure out error handling. | |
272 DCHECK(false); | |
273 } | |
274 | |
275 void ViewTexture::ConvertBitmapToD3DData( | |
276 const SkBitmap& bitmap, | |
277 scoped_array<uint32>* converted_data) { | |
278 int width = bitmap.width(); | |
279 int height = bitmap.height(); | |
280 SkAutoLockPixels pixel_lock(bitmap); | |
281 // D3D wants colors in ABGR format (premultiplied). | |
282 converted_data->reset(new uint32[width * height]); | |
283 uint32_t* bitmap_data = bitmap.getAddr32(0, 0); | |
284 for (int x = 0, offset = 0; x < width; ++x) { | |
285 for (int y = 0; y < height; ++y, ++offset) { | |
286 SkColor color = bitmap_data[offset]; | |
287 (*converted_data)[offset] = | |
288 (SkColorGetA(color) << 24) | | |
289 (SkColorGetB(color) << 16) | | |
290 (SkColorGetG(color) << 8) | | |
291 (SkColorGetR(color)); | |
292 } | |
293 } | |
294 } | |
295 | |
296 void ViewTexture::CreateVertexBufferForRegion(const gfx::Rect& bounds) { | |
297 vertex_buffer_.Release(); | |
298 float x = bounds.x(); | |
299 float max_x = bounds.right(); | |
300 float y = bounds.y(); | |
301 float max_y = bounds.bottom(); | |
302 float tex_x = x / static_cast<float>(view_size_.width()); | |
303 float max_tex_x = max_x / static_cast<float>(view_size_.width()); | |
304 float tex_y = y / static_cast<float>(view_size_.width()); | |
305 float max_tex_y = max_y / static_cast<float>(view_size_.height()); | |
306 Vertex vertices[] = { | |
307 { D3DXVECTOR3( x, -max_y, 0.0f), D3DXVECTOR2( tex_x, max_tex_y) }, | |
308 { D3DXVECTOR3( x, -y, 0.0f), D3DXVECTOR2( tex_x, tex_y) }, | |
309 { D3DXVECTOR3(max_x, -y, 0.0f), D3DXVECTOR2(max_tex_x, tex_y) }, | |
310 { D3DXVECTOR3(max_x, -max_y, 0.0f), D3DXVECTOR2(max_tex_x, max_tex_y) } | |
311 }; | |
312 | |
313 // Create the vertex buffer containing the points. | |
314 D3D10_BUFFER_DESC buffer_desc; | |
315 buffer_desc.Usage = D3D10_USAGE_IMMUTABLE; | |
316 buffer_desc.ByteWidth = sizeof(Vertex) * ARRAYSIZE_UNSAFE(vertices); | |
317 buffer_desc.BindFlags = D3D10_BIND_VERTEX_BUFFER; | |
318 buffer_desc.CPUAccessFlags = 0; | |
319 buffer_desc.MiscFlags = 0; | |
320 D3D10_SUBRESOURCE_DATA init_data; | |
321 init_data.pSysMem = vertices; | |
322 RETURN_IF_FAILED(device_->CreateBuffer(&buffer_desc, &init_data, | |
323 vertex_buffer_.Receive())); | |
324 } | |
325 | |
326 CompositorWin::CompositorWin(CompositorDelegate* delegate, | |
327 gfx::AcceleratedWidget widget, | |
328 const gfx::Size& size) | |
329 : Compositor(delegate, size), | |
330 host_(widget), | |
331 technique_(NULL) { | |
332 } | |
333 | |
334 void CompositorWin::Init() { | |
335 CreateDevice(); | |
336 LoadEffects(); | |
337 OnWidgetSizeChanged(); | |
338 InitVertexLayout(); | |
339 CreateVertexBuffer(); | |
340 CreateIndexBuffer(); | |
341 } | |
342 | |
343 void CompositorWin::UpdatePerspective(const ui::Transform& transform, | |
344 const gfx::Size& view_size) { | |
345 float transform_data_buffer[16]; | |
346 transform.matrix().asColMajorf(transform_data_buffer); | |
347 D3DXMATRIX transform_matrix(&transform_data_buffer[0]); | |
348 std::swap(transform_matrix._12, transform_matrix._21); | |
349 std::swap(transform_matrix._13, transform_matrix._31); | |
350 std::swap(transform_matrix._23, transform_matrix._32); | |
351 | |
352 // Different coordinate system; flip the y. | |
353 transform_matrix._42 *= -1; | |
354 | |
355 // Scale so x and y are from 0-2. | |
356 D3DXMATRIX scale_matrix; | |
357 D3DXMatrixScaling( | |
358 &scale_matrix, | |
359 2.0f / static_cast<float>(size().width()), | |
360 2.0f / static_cast<float>(size().height()), | |
361 1.0f); | |
362 | |
363 // Translate so x and y are from -1,-1 to 1,1. | |
364 D3DXMATRIX translate_matrix; | |
365 D3DXMatrixTranslation(&translate_matrix, -1.0f, 1.0f, 0.0f); | |
366 | |
367 D3DXMATRIX projection_matrix; | |
368 D3DXMatrixIdentity(&projection_matrix); | |
369 D3DXMatrixPerspectiveFovLH(&projection_matrix, | |
370 atanf(.5f) * 2.0f, 1.0f, 1.0f, 1000.0f); | |
371 D3DXVECTOR3 pos(0.0f, 0.0f, -2.0f); | |
372 D3DXVECTOR3 target(0.0f, 0.0f, 0.0f); | |
373 D3DXVECTOR3 up(0.0f, 1.0f, 0.0f); | |
374 D3DXMATRIX view; | |
375 D3DXMatrixIdentity(&view); | |
376 D3DXMatrixLookAtLH(&view, &pos, &target, &up); | |
377 | |
378 D3DXMATRIX wvp = transform_matrix * scale_matrix * translate_matrix * view * | |
379 projection_matrix; | |
380 | |
381 fx_->GetVariableByName("gWVP")->AsMatrix()->SetMatrix(wvp); | |
382 } | |
383 | |
384 ID3D10Buffer* CompositorWin::GetTextureIndexBuffer() { | |
385 return index_buffer_.get(); | |
386 } | |
387 | |
388 Texture* CompositorWin::CreateTexture() { | |
389 return new ViewTexture(this, device_.get(), fx_.get()); | |
390 } | |
391 | |
392 void CompositorWin::OnNotifyStart(bool clear) { | |
393 ID3D10RenderTargetView* target_view = main_render_target_view_.get(); | |
394 device_->OMSetRenderTargets(1, &target_view, depth_stencil_view_.get()); | |
395 | |
396 // Clear the background and stencil view. | |
397 // TODO(vollick) see if |clear| can be used to avoid unnecessary clearing. | |
398 device_->ClearRenderTargetView(target_view, | |
399 D3DXCOLOR(0.0f, 0.0f, 0.0f, 0.0f)); | |
400 device_->ClearDepthStencilView( | |
401 depth_stencil_view_.get(), D3D10_CLEAR_DEPTH|D3D10_CLEAR_STENCIL, | |
402 1.0f, 0); | |
403 | |
404 // TODO: these steps may not be necessary each time through. | |
405 device_->OMSetDepthStencilState(0, 0); | |
406 float blend_factors[] = {0.0f, 0.0f, 0.0f, 0.0f}; | |
407 device_->OMSetBlendState(0, blend_factors, 0xffffffff); | |
408 device_->IASetInputLayout(vertex_layout_.get()); | |
409 device_->IASetPrimitiveTopology(D3D10_PRIMITIVE_TOPOLOGY_TRIANGLELIST); | |
410 } | |
411 | |
412 void CompositorWin::OnNotifyEnd() { | |
413 // Copy from main_render_target_view_| (where all are rendering was done) back | |
414 // to |dest_render_target_view_|. | |
415 ID3D10RenderTargetView* target_view = dest_render_target_view_.get(); | |
416 device_->OMSetRenderTargets(1, &target_view, NULL); | |
417 device_->ClearRenderTargetView(target_view, | |
418 D3DXCOLOR(0.0f, 0.0f, 0.0f, 0.0f)); | |
419 RETURN_IF_FAILED( | |
420 fx_->GetVariableByName("textureMap")->AsShaderResource()-> | |
421 SetResource(main_texture_shader_view_.get())); | |
422 D3DXMATRIX identify_matrix; | |
423 D3DXMatrixIdentity(&identify_matrix); | |
424 fx_->GetVariableByName("gWVP")->AsMatrix()->SetMatrix(identify_matrix); | |
425 ID3D10EffectTechnique* technique = fx_->GetTechniqueByName("ViewTech"); | |
426 DCHECK(technique); | |
427 D3D10_TECHNIQUE_DESC tech_desc; | |
428 technique->GetDesc(&tech_desc); | |
429 for(UINT p = 0; p < tech_desc.Passes; ++p) | |
430 technique->GetPassByIndex(p)->Apply(0); | |
431 UINT stride = sizeof(Vertex); | |
432 UINT offset = 0; | |
433 ID3D10Buffer* vertex_buffer = vertex_buffer_.get(); | |
434 device_->IASetVertexBuffers(0, 1, &vertex_buffer, &stride, &offset); | |
435 device_->IASetIndexBuffer(index_buffer_.get(), DXGI_FORMAT_R32_UINT, 0); | |
436 device_->DrawIndexed(6, 0, 0); | |
437 RETURN_IF_FAILED( | |
438 fx_->GetVariableByName("textureMap")->AsShaderResource()-> | |
439 SetResource(NULL)); | |
440 swap_chain_->Present(0, 0); | |
441 | |
442 // We may delete the shader resource view before drawing again. Unset it so | |
443 // that d3d doesn't generate a warning when we do that. | |
444 fx_->GetVariableByName("textureMap")->AsShaderResource()->SetResource(NULL); | |
445 for(UINT i = 0; i < tech_desc.Passes; ++i) | |
446 technique_->GetPassByIndex(i)->Apply(0); | |
447 } | |
448 | |
449 void CompositorWin::Blur(const gfx::Rect& bounds) { | |
450 // Set up the vertex buffer for the region we're going to blur. | |
451 ScopedComPtr<ID3D10Buffer> scoped_vertex_buffer( | |
452 CreateVertexBufferForRegion(bounds)); | |
453 ID3D10Buffer* vertex_buffer = scoped_vertex_buffer.get(); | |
454 UINT stride = sizeof(Vertex); | |
455 UINT offset = 0; | |
456 device_->IASetVertexBuffers(0, 1, &vertex_buffer, &stride, &offset); | |
457 device_->IASetIndexBuffer(index_buffer_.get(), DXGI_FORMAT_R32_UINT, 0); | |
458 device_->DrawIndexed(6, 0, 0); | |
459 D3DXMATRIX identity_matrix; | |
460 D3DXMatrixIdentity(&identity_matrix); | |
461 | |
462 // Horizontal blur from the main texture to blur texture. | |
463 UpdateBlurKernel(HORIZONTAL, size().width()); | |
464 ID3D10RenderTargetView* target_view = blur_render_target_view_.get(); | |
465 device_->OMSetRenderTargets(1, &target_view, NULL); | |
466 RETURN_IF_FAILED( | |
467 blur_fx_->GetVariableByName("textureMap")->AsShaderResource()-> | |
468 SetResource(main_texture_shader_view_.get())); | |
469 blur_fx_->GetVariableByName("gWVP")->AsMatrix()->SetMatrix( | |
470 identity_matrix); | |
471 ID3D10EffectTechnique* technique = blur_fx_->GetTechniqueByName("ViewTech"); | |
472 DCHECK(technique); | |
473 D3D10_TECHNIQUE_DESC tech_desc; | |
474 technique->GetDesc(&tech_desc); | |
475 for(UINT p = 0; p < tech_desc.Passes; ++p) | |
476 technique->GetPassByIndex(p)->Apply(0); | |
477 device_->DrawIndexed(6, 0, 0); | |
478 | |
479 { | |
480 // We do this to avoid a warning. | |
481 ID3D10ShaderResourceView* tmp = NULL; | |
482 device_->PSSetShaderResources(0, 1, &tmp); | |
483 } | |
484 | |
485 // Vertical blur from the blur texture back to main buffer. | |
486 RETURN_IF_FAILED( | |
487 blur_fx_->GetVariableByName("textureMap")->AsShaderResource()-> | |
488 SetResource(blur_texture_shader_view_.get())); | |
489 UpdateBlurKernel(VERTICAL, size().height()); | |
490 target_view = main_render_target_view_.get(); | |
491 device_->OMSetRenderTargets(1, &target_view, NULL); | |
492 for(UINT p = 0; p < tech_desc.Passes; ++p) | |
493 technique->GetPassByIndex(p)->Apply(0); | |
494 device_->DrawIndexed(6, 0, 0); | |
495 | |
496 #if !defined(NDEBUG) | |
497 // A warning is generated if a bound vertexbuffer is deleted. To avoid that | |
498 // warning we reset the buffer here. We only do it for debug builds as it's | |
499 // ok to effectively unbind the vertex buffer. | |
500 vertex_buffer = vertex_buffer_.get(); | |
501 device_->IASetVertexBuffers(0, 1, &vertex_buffer, &stride, &offset); | |
502 device_->IASetIndexBuffer(index_buffer_.get(), DXGI_FORMAT_R32_UINT, 0); | |
503 #endif | |
504 } | |
505 | |
506 bool CompositorWin::ReadPixels(SkBitmap* bitmap, const gfx::Rect& bounds) { | |
507 NOTIMPLEMENTED(); | |
508 return false; | |
509 } | |
510 | |
511 void CompositorWin::OnWidgetSizeChanged() { | |
512 dest_render_target_view_ = NULL; | |
513 depth_stencil_buffer_ = NULL; | |
514 depth_stencil_view_ = NULL; | |
515 | |
516 main_render_target_view_ = NULL; | |
517 main_texture_ = NULL; | |
518 main_texture_shader_view_ = NULL; | |
519 | |
520 blur_render_target_view_ = NULL; | |
521 blur_texture_ = NULL; | |
522 blur_texture_shader_view_ = NULL; | |
523 | |
524 CreateTexture(size(), main_texture_.Receive(), | |
525 main_render_target_view_.Receive(), | |
526 main_texture_shader_view_.Receive()); | |
527 | |
528 CreateTexture(size(), blur_texture_.Receive(), | |
529 blur_render_target_view_.Receive(), | |
530 blur_texture_shader_view_.Receive()); | |
531 | |
532 // Resize the swap chain and recreate the render target view. | |
533 RETURN_IF_FAILED(swap_chain_->ResizeBuffers( | |
534 1, size().width(), size().height(), DXGI_FORMAT_R8G8B8A8_UNORM, 0)); | |
535 ScopedComPtr<ID3D10Texture2D> back_buffer; | |
536 RETURN_IF_FAILED(swap_chain_->GetBuffer( | |
537 0, __uuidof(ID3D10Texture2D), | |
538 reinterpret_cast<void**>(back_buffer.Receive()))); | |
539 RETURN_IF_FAILED(device_->CreateRenderTargetView( | |
540 back_buffer.get(), 0, | |
541 dest_render_target_view_.Receive())); | |
542 | |
543 // Create the depth/stencil buffer and view. | |
544 D3D10_TEXTURE2D_DESC depth_stencil_desc; | |
545 depth_stencil_desc.Width = size().width(); | |
546 depth_stencil_desc.Height = size().height(); | |
547 depth_stencil_desc.MipLevels = 1; | |
548 depth_stencil_desc.ArraySize = 1; | |
549 depth_stencil_desc.Format = DXGI_FORMAT_D24_UNORM_S8_UINT; | |
550 depth_stencil_desc.SampleDesc.Count = 1; // multisampling must match | |
551 depth_stencil_desc.SampleDesc.Quality = 0; // swap chain values. | |
552 depth_stencil_desc.Usage = D3D10_USAGE_DEFAULT; | |
553 depth_stencil_desc.BindFlags = D3D10_BIND_DEPTH_STENCIL; | |
554 depth_stencil_desc.CPUAccessFlags = 0; | |
555 depth_stencil_desc.MiscFlags = 0; | |
556 | |
557 RETURN_IF_FAILED(device_->CreateTexture2D(&depth_stencil_desc, 0, | |
558 depth_stencil_buffer_.Receive())); | |
559 RETURN_IF_FAILED(device_->CreateDepthStencilView( | |
560 depth_stencil_buffer_.get(), 0, | |
561 depth_stencil_view_.Receive())); | |
562 | |
563 | |
564 // Set the viewport transform. | |
565 D3D10_VIEWPORT vp; | |
566 vp.TopLeftX = 0; | |
567 vp.TopLeftY = 0; | |
568 vp.Width = size().width(); | |
569 vp.Height = size().height(); | |
570 vp.MinDepth = 0.0f; | |
571 vp.MaxDepth = 1.0f; | |
572 | |
573 device_->RSSetViewports(1, &vp); | |
574 } | |
575 | |
576 CompositorWin::~CompositorWin() { | |
577 } | |
578 | |
579 void CompositorWin::Errored(HRESULT error_code) { | |
580 // TODO: figure out error handling. | |
581 DCHECK(false); | |
582 } | |
583 | |
584 void CompositorWin::CreateDevice() { | |
585 DXGI_SWAP_CHAIN_DESC sd; | |
586 sd.BufferDesc.Width = size().width(); | |
587 sd.BufferDesc.Height = size().height(); | |
588 sd.BufferDesc.RefreshRate.Numerator = 60; | |
589 sd.BufferDesc.RefreshRate.Denominator = 1; | |
590 sd.BufferDesc.Format = DXGI_FORMAT_R8G8B8A8_UNORM; | |
591 sd.BufferDesc.ScanlineOrdering = DXGI_MODE_SCANLINE_ORDER_UNSPECIFIED; | |
592 sd.BufferDesc.Scaling = DXGI_MODE_SCALING_UNSPECIFIED; | |
593 | |
594 // No multisampling. | |
595 sd.SampleDesc.Count = 1; | |
596 sd.SampleDesc.Quality = 0; | |
597 | |
598 sd.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT; | |
599 sd.BufferCount = 1; | |
600 sd.OutputWindow = host_; | |
601 sd.Windowed = true; | |
602 sd.SwapEffect = DXGI_SWAP_EFFECT_DISCARD; | |
603 sd.Flags = 0; | |
604 | |
605 // Create the device. | |
606 UINT createDeviceFlags = 0; | |
607 #if !defined(NDEBUG) | |
608 createDeviceFlags |= D3D10_CREATE_DEVICE_DEBUG; | |
609 #endif | |
610 RETURN_IF_FAILED( | |
611 D3D10CreateDeviceAndSwapChain( | |
612 0, //default adapter | |
613 D3D10_DRIVER_TYPE_HARDWARE, | |
614 0, // no software device | |
615 createDeviceFlags, | |
616 D3D10_SDK_VERSION, | |
617 &sd, | |
618 swap_chain_.Receive(), | |
619 device_.Receive())); | |
620 } | |
621 | |
622 void CompositorWin::LoadEffects() { | |
623 DWORD shader_flags = D3D10_SHADER_ENABLE_STRICTNESS; | |
624 #if !defined(NDEBUG) | |
625 shader_flags |= D3D10_SHADER_DEBUG | D3D10_SHADER_SKIP_OPTIMIZATION; | |
626 #endif | |
627 ScopedComPtr<ID3D10Blob> compilation_errors; | |
628 const base::StringPiece& fx_data = ResourceBundle::GetSharedInstance(). | |
629 GetRawDataResource(IDR_COMPOSITOR_FX); | |
630 DCHECK(!fx_data.empty()); | |
631 RETURN_IF_FAILED( | |
632 D3DX10CreateEffectFromMemory( | |
633 fx_data.data(), fx_data.size(), "compositor.fx", NULL, NULL, | |
634 "fx_4_0", shader_flags, 0, device_.get(), NULL, NULL, fx_.Receive(), | |
635 compilation_errors.Receive(), NULL)); | |
636 technique_ = fx_->GetTechniqueByName("ViewTech"); | |
637 DCHECK(technique_); | |
638 | |
639 const base::StringPiece& blur_data = ResourceBundle::GetSharedInstance(). | |
640 GetRawDataResource(IDR_BLUR_FX); | |
641 DCHECK(!blur_data.empty()); | |
642 compilation_errors = NULL; | |
643 RETURN_IF_FAILED( | |
644 D3DX10CreateEffectFromMemory( | |
645 blur_data.data(), blur_data.size(), "bloom.fx", NULL, NULL, | |
646 "fx_4_0", shader_flags, 0, device_.get(), NULL, NULL, | |
647 blur_fx_.Receive(), compilation_errors.Receive(), NULL)); | |
648 blur_technique_ = blur_fx_->GetTechniqueByName("ViewTech"); | |
649 DCHECK(blur_technique_); | |
650 } | |
651 | |
652 void CompositorWin::InitVertexLayout() { | |
653 D3D10_INPUT_ELEMENT_DESC vertex_desc[] = { | |
654 { "POSITION", 0, DXGI_FORMAT_R32G32B32_FLOAT, 0, 0, | |
655 D3D10_INPUT_PER_VERTEX_DATA, 0 }, | |
656 { "TEXC", 0, DXGI_FORMAT_R32G32_FLOAT, 0, 12, | |
657 D3D10_INPUT_PER_VERTEX_DATA, 0 }, | |
658 }; | |
659 | |
660 // Create the input layout | |
661 D3D10_PASS_DESC pass_desc; | |
662 RETURN_IF_FAILED(technique_->GetPassByIndex(0)->GetDesc(&pass_desc)); | |
663 RETURN_IF_FAILED( | |
664 device_->CreateInputLayout(vertex_desc, ARRAYSIZE_UNSAFE(vertex_desc), | |
665 pass_desc.pIAInputSignature, | |
666 pass_desc.IAInputSignatureSize, | |
667 vertex_layout_.Receive())); | |
668 } | |
669 | |
670 void CompositorWin::UpdateBlurKernel(Direction direction, int size) { | |
671 // Update the blur data. | |
672 const int kSize = 13; | |
673 float pixel_data[4 * kSize]; | |
674 memset(pixel_data, 0, sizeof(float) * 4 * kSize); | |
675 for (int i = 0; i < kSize; ++i) { | |
676 pixel_data[i * 4 + ((direction == HORIZONTAL) ? 0 : 1)] = | |
677 static_cast<float>(i - (kSize / 2)) / static_cast<float>(size); | |
678 } | |
679 RETURN_IF_FAILED(blur_fx_->GetVariableByName("TexelKernel")->AsVector()-> | |
680 SetFloatVectorArray(pixel_data, 0, kSize)); | |
681 } | |
682 | |
683 void CompositorWin::CreateTexture( | |
684 const gfx::Size& size, | |
685 ID3D10Texture2D** texture, | |
686 ID3D10RenderTargetView** render_target_view, | |
687 ID3D10ShaderResourceView** shader_resource_view) { | |
688 D3D10_TEXTURE2D_DESC texture_desc; | |
689 texture_desc.Width = size.width(); | |
690 texture_desc.Height = size.height(); | |
691 texture_desc.MipLevels = 1; | |
692 texture_desc.Format = DXGI_FORMAT_R8G8B8A8_UNORM; | |
693 texture_desc.SampleDesc.Count = 1; | |
694 texture_desc.SampleDesc.Quality = 0; | |
695 texture_desc.Usage = D3D10_USAGE_DEFAULT; | |
696 texture_desc.BindFlags = | |
697 D3D10_BIND_RENDER_TARGET | D3D10_BIND_SHADER_RESOURCE; | |
698 texture_desc.CPUAccessFlags = 0; | |
699 texture_desc.MiscFlags = 0; | |
700 texture_desc.ArraySize = 1; | |
701 RETURN_IF_FAILED(device_->CreateTexture2D(&texture_desc, NULL, texture)); | |
702 | |
703 RETURN_IF_FAILED( | |
704 device_->CreateShaderResourceView(*texture, NULL, shader_resource_view)); | |
705 | |
706 D3D10_RENDER_TARGET_VIEW_DESC render_target_view_desc; | |
707 render_target_view_desc.Format = texture_desc.Format; | |
708 render_target_view_desc.ViewDimension = D3D10_RTV_DIMENSION_TEXTURE2DMS; | |
709 render_target_view_desc.Texture2D.MipSlice = 0; | |
710 RETURN_IF_FAILED(device_->CreateRenderTargetView( | |
711 *texture, &render_target_view_desc, render_target_view)); | |
712 } | |
713 | |
714 void CompositorWin::CreateVertexBuffer() { | |
715 vertex_buffer_.Release(); | |
716 | |
717 Vertex vertices[] = { | |
718 { D3DXVECTOR3(-1.0f, -1.0f, 0.0f), D3DXVECTOR2(0.0f, 1.0f) }, | |
719 { D3DXVECTOR3(-1.0f, 1.0f, 0.0f), D3DXVECTOR2(0.0f, 0.0f) }, | |
720 { D3DXVECTOR3( 1.0f, 1.0f, 0.0f), D3DXVECTOR2(1.0f, 0.0f) }, | |
721 { D3DXVECTOR3( 1.0f, -1.0f, 0.0f), D3DXVECTOR2(1.0f, 1.0f) }, | |
722 }; | |
723 | |
724 // Create the vertex buffer containing the points. | |
725 D3D10_BUFFER_DESC buffer_desc; | |
726 buffer_desc.Usage = D3D10_USAGE_IMMUTABLE; | |
727 buffer_desc.ByteWidth = sizeof(Vertex) * ARRAYSIZE_UNSAFE(vertices); | |
728 buffer_desc.BindFlags = D3D10_BIND_VERTEX_BUFFER; | |
729 buffer_desc.CPUAccessFlags = 0; | |
730 buffer_desc.MiscFlags = 0; | |
731 D3D10_SUBRESOURCE_DATA init_data; | |
732 init_data.pSysMem = vertices; | |
733 RETURN_IF_FAILED(device_->CreateBuffer(&buffer_desc, &init_data, | |
734 vertex_buffer_.Receive())); | |
735 } | |
736 | |
737 void CompositorWin::CreateIndexBuffer() { | |
738 index_buffer_.Release(); | |
739 | |
740 // Then the index buffer. | |
741 DWORD indices[] = { | |
742 0, 1, 2, | |
743 0, 2, 3, | |
744 }; | |
745 D3D10_BUFFER_DESC index_buffer; | |
746 index_buffer.Usage = D3D10_USAGE_IMMUTABLE; | |
747 index_buffer.ByteWidth = sizeof(DWORD) * ARRAYSIZE_UNSAFE(indices); | |
748 index_buffer.BindFlags = D3D10_BIND_INDEX_BUFFER; | |
749 index_buffer.CPUAccessFlags = 0; | |
750 index_buffer.MiscFlags = 0; | |
751 D3D10_SUBRESOURCE_DATA init_data; | |
752 init_data.pSysMem = indices; | |
753 RETURN_IF_FAILED(device_->CreateBuffer(&index_buffer, &init_data, | |
754 index_buffer_.Receive())); | |
755 } | |
756 | |
757 ID3D10Buffer* CompositorWin::CreateVertexBufferForRegion( | |
758 const gfx::Rect& bounds) { | |
759 float x = static_cast<float>(bounds.x()) / | |
760 static_cast<float>(size().width()) * 2.0f - 1.0f; | |
761 float max_x = | |
762 x + bounds.width() / static_cast<float>(size().width()) * 2.0f; | |
763 float y = | |
764 static_cast<float>(size().height() - bounds.y() - bounds.height()) / | |
765 static_cast<float>(size().height()) * 2.0f - 1.0f; | |
766 float max_y = | |
767 y + bounds.height() / static_cast<float>(size().height()) * 2.0f; | |
768 float tex_x = x / 2.0f + .5f; | |
769 float max_tex_x = max_x / 2.0f + .5f; | |
770 float tex_y = 1.0f - (max_y + 1.0f) / 2.0f; | |
771 float max_tex_y = tex_y + (max_y - y) / 2.0f; | |
772 Vertex vertices[] = { | |
773 { D3DXVECTOR3( x, y, 0.0f), D3DXVECTOR2( tex_x, max_tex_y) }, | |
774 { D3DXVECTOR3( x, max_y, 0.0f), D3DXVECTOR2( tex_x, tex_y) }, | |
775 { D3DXVECTOR3(max_x, max_y, 0.0f), D3DXVECTOR2(max_tex_x, tex_y) }, | |
776 { D3DXVECTOR3(max_x, y, 0.0f), D3DXVECTOR2(max_tex_x, max_tex_y) }, | |
777 }; | |
778 | |
779 // Create the vertex buffer containing the points. | |
780 D3D10_BUFFER_DESC buffer_desc; | |
781 buffer_desc.Usage = D3D10_USAGE_IMMUTABLE; | |
782 buffer_desc.ByteWidth = sizeof(Vertex) * ARRAYSIZE_UNSAFE(vertices); | |
783 buffer_desc.BindFlags = D3D10_BIND_VERTEX_BUFFER; | |
784 buffer_desc.CPUAccessFlags = 0; | |
785 buffer_desc.MiscFlags = 0; | |
786 D3D10_SUBRESOURCE_DATA init_data; | |
787 init_data.pSysMem = vertices; | |
788 ID3D10Buffer* vertex_buffer = NULL; | |
789 // TODO: better error handling. | |
790 int error_code = | |
791 device_->CreateBuffer(&buffer_desc, &init_data, &vertex_buffer); | |
792 if (error_code != S_OK) { | |
793 Errored(error_code); | |
794 return NULL; | |
795 } | |
796 return vertex_buffer; | |
797 } | |
798 | |
799 } // namespace | |
800 | |
801 // static | |
802 Compositor* Compositor::Create(CompositorDelegate* delegate, | |
803 gfx::AcceleratedWidget widget, | |
804 const gfx::Size& size) { | |
805 CompositorWin* compositor = new CompositorWin(delegate, widget, size); | |
806 compositor->Init(); | |
807 return compositor; | |
808 } | |
809 | |
810 } // namespace ui | |
OLD | NEW |