diff options
author | nick@chromium.org <nick@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2013-01-04 18:53:44 +0000 |
---|---|---|
committer | nick@chromium.org <nick@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2013-01-04 18:53:44 +0000 |
commit | 54e74d6c572f2c872e425a2143b8579e4cb8f66c (patch) | |
tree | e89ac35948eeba895500224575dae836087ff05a /ui/surface | |
parent | 8c6b319b0be38d10350a95d4c2cb30b2239536ee (diff) | |
download | chromium_src-54e74d6c572f2c872e425a2143b8579e4cb8f66c.zip chromium_src-54e74d6c572f2c872e425a2143b8579e4cb8f66c.tar.gz chromium_src-54e74d6c572f2c872e425a2143b8579e4cb8f66c.tar.bz2 |
Revert 175152
> [ui/surface] Separate image processing logic from presentation logic.
>
> The D3D image processing code from AcceleratedPresenter moves to its own class, "ui/surface/accelerated_surface_transformer_win.h". This split allows the image processing code to be tested independently of the present-scheduling system, and so we add unit tests doing exactly that. Utility functions (loading d3d, creating temp surfaces) doing things commonly required by test, transform, and present code -- these functions are moved to a third location, "ui/surface/d3d9_utils_win.h"
>
> The new unit tests -- which live in the ui_unittests binary -- make extensive use of pseudorandom image content, which I think is kind of neat. The tests use D3D HAL devices; I tried to use REF, but it didn't work, as StretchRect+LINEAR is not supported by refrast. So as a result we may have a GPU vendor dependency in these results.
>
> BUG=161537
> TEST=new ui_unittests
>
> Committed: https://src.chromium.org/viewvc/chrome?view=rev&revision=174028
>
> Committed: https://src.chromium.org/viewvc/chrome?view=rev&revision=174338
>
> Committed: https://src.chromium.org/viewvc/chrome?view=rev&revision=174943
>
> Review URL: https://codereview.chromium.org/11464017
TBR=nick@chromium.org
Review URL: https://codereview.chromium.org/11753031
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@175161 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'ui/surface')
-rw-r--r-- | ui/surface/accelerated_surface_transformer_win.cc | 261 | ||||
-rw-r--r-- | ui/surface/accelerated_surface_transformer_win.h | 81 | ||||
-rw-r--r-- | ui/surface/accelerated_surface_transformer_win_unittest.cc | 525 | ||||
-rw-r--r-- | ui/surface/accelerated_surface_win.cc | 280 | ||||
-rw-r--r-- | ui/surface/accelerated_surface_win.hlsl (renamed from ui/surface/accelerated_surface_transformer_win.hlsl) | 4 | ||||
-rw-r--r-- | ui/surface/d3d9_utils_win.cc | 119 | ||||
-rw-r--r-- | ui/surface/d3d9_utils_win.h | 71 | ||||
-rw-r--r-- | ui/surface/surface.gyp | 6 |
8 files changed, 240 insertions, 1107 deletions
diff --git a/ui/surface/accelerated_surface_transformer_win.cc b/ui/surface/accelerated_surface_transformer_win.cc deleted file mode 100644 index cfc031b..0000000 --- a/ui/surface/accelerated_surface_transformer_win.cc +++ /dev/null @@ -1,261 +0,0 @@ -// Copyright (c) 2012 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "ui/surface/accelerated_surface_transformer_win.h"
-
-#include <vector>
-
-#include "accelerated_surface_transformer_win_hlsl_compiled.h"
-#include "base/debug/trace_event.h"
-#include "base/memory/ref_counted.h"
-#include "base/single_thread_task_runner.h"
-#include "base/synchronization/lock.h"
-#include "base/synchronization/waitable_event.h"
-#include "base/win/scoped_comptr.h"
-#include "ui/gfx/native_widget_types.h"
-#include "ui/gfx/rect.h"
-#include "ui/gfx/size.h"
-#include "ui/surface/d3d9_utils_win.h"
-#include "ui/surface/surface_export.h"
-
-using base::win::ScopedComPtr;
-using std::vector;
-
-namespace d3d_utils = ui_surface_d3d9_utils;
-
-namespace {
-
-struct Vertex {
- float x, y, z, w;
- float u, v;
-};
-
-const static D3DVERTEXELEMENT9 g_vertexElements[] = {
- { 0, 0, D3DDECLTYPE_FLOAT4, 0, D3DDECLUSAGE_POSITION, 0 },
- { 0, 16, D3DDECLTYPE_FLOAT2, 0, D3DDECLUSAGE_TEXCOORD, 0 },
- D3DDECL_END()
-};
-
-// Calculate the number necessary to transform |src_subrect| into |dst_size|
-// by repeating downsampling of the image of |src_subrect| by a factor no more
-// than 2.
-int GetResampleCount(const gfx::Rect& src_subrect,
- const gfx::Size& dst_size,
- const gfx::Size& back_buffer_size) {
- // At least one copy is required, since the back buffer itself is not
- // lockable.
- int min_resample_count = 1;
- int width_count = 0;
- int width = src_subrect.width();
- while (width > dst_size.width()) {
- ++width_count;
- width >>= 1;
- }
- int height_count = 0;
- int height = src_subrect.height();
- while (height > dst_size.height()) {
- ++height_count;
- height >>= 1;
- }
- return std::max(std::max(width_count, height_count),
- min_resample_count);
-}
-
-// Returns half the size of |size| no smaller than |min_size|.
-gfx::Size GetHalfSizeNoLessThan(const gfx::Size& size,
- const gfx::Size& min_size) {
- return gfx::Size(std::max(min_size.width(), size.width() / 2),
- std::max(min_size.height(), size.height() / 2));
-}
-
-gfx::Size GetSize(IDirect3DSurface9* surface) {
- D3DSURFACE_DESC surface_description;
- HRESULT hr = surface->GetDesc(&surface_description);
- if (FAILED(hr))
- return gfx::Size(0, 0);
- return gfx::Size(surface_description.Width, surface_description.Height);
-}
-
-} // namespace
-
-
-AcceleratedSurfaceTransformer::AcceleratedSurfaceTransformer() {}
-
-bool AcceleratedSurfaceTransformer::Init(IDirect3DDevice9* device) {
- device_ = device;
- if (!InitShaderCombo(
- ui_surface::AcceleratedSurfaceTransformerWinHLSL::kVsOneTexture,
- ui_surface::AcceleratedSurfaceTransformerWinHLSL::kPsOneTexture,
- SIMPLE_TEXTURE)) {
- ReleaseAll();
- return false;
- }
-
- base::win::ScopedComPtr<IDirect3DVertexDeclaration9> vertex_declaration;
- HRESULT hr = device_->CreateVertexDeclaration(g_vertexElements,
- vertex_declaration.Receive());
- if (!SUCCEEDED(hr)) {
- ReleaseAll();
- return false;
- }
- device_->SetVertexDeclaration(vertex_declaration);
-
- return true;
-}
-
-bool AcceleratedSurfaceTransformer::InitShaderCombo(
- const BYTE vertex_shader_instructions[],
- const BYTE pixel_shader_instructions[],
- ShaderCombo shader_combo_name) {
- HRESULT hr = device_->CreateVertexShader(
- reinterpret_cast<const DWORD*>(vertex_shader_instructions),
- vertex_shaders_[shader_combo_name].Receive());
-
- if (FAILED(hr))
- return false;
-
- hr = device_->CreatePixelShader(
- reinterpret_cast<const DWORD*>(pixel_shader_instructions),
- pixel_shaders_[shader_combo_name].Receive());
-
- return SUCCEEDED(hr);
-}
-
-
-void AcceleratedSurfaceTransformer::ReleaseAll() {
- for (int i = 0; i < NUM_SHADERS; i++) {
- vertex_shaders_[i] = NULL;
- vertex_shaders_[i] = NULL;
- }
- device_ = NULL;
-}
-void AcceleratedSurfaceTransformer::DetachAll() {
- for (int i = 0; i < NUM_SHADERS; i++) {
- vertex_shaders_[i].Detach();
- vertex_shaders_[i].Detach();
- }
- device_.Detach();
-}
-
-// Draw a textured quad to a surface.
-bool AcceleratedSurfaceTransformer::CopyInverted(
- IDirect3DTexture9* src_texture,
- IDirect3DSurface9* dst_surface,
- const gfx::Size& dst_size) {
- base::win::ScopedComPtr<IDirect3DSurface9> default_color_target;
- device()->GetRenderTarget(0, default_color_target.Receive());
-
- if (!SetShaderCombo(SIMPLE_TEXTURE))
- return false;
-
- device()->SetRenderTarget(0, dst_surface);
- device()->SetTexture(0, src_texture);
-
- D3DVIEWPORT9 viewport = {
- 0, 0,
- dst_size.width(), dst_size.height(),
- 0, 1
- };
- device()->SetViewport(&viewport);
-
- float halfPixelX = -1.0f / dst_size.width();
- float halfPixelY = 1.0f / dst_size.height();
- Vertex vertices[] = {
- { halfPixelX - 1, halfPixelY + 1, 0.5f, 1, 0, 1 },
- { halfPixelX + 1, halfPixelY + 1, 0.5f, 1, 1, 1 },
- { halfPixelX + 1, halfPixelY - 1, 0.5f, 1, 1, 0 },
- { halfPixelX - 1, halfPixelY - 1, 0.5f, 1, 0, 0 }
- };
-
- device()->BeginScene();
- device()->DrawPrimitiveUP(D3DPT_TRIANGLEFAN,
- 2,
- vertices,
- sizeof(vertices[0]));
- device()->EndScene();
-
- // Clear surface references.
- device()->SetRenderTarget(0, default_color_target);
- device()->SetTexture(0, NULL);
- return true;
-}
-
-// Resize an RGB surface using repeated linear interpolation.
-bool AcceleratedSurfaceTransformer::ResizeBilinear(
- IDirect3DSurface9* src_surface,
- const gfx::Rect& src_subrect,
- IDirect3DSurface9* dst_surface) {
- gfx::Size src_size = GetSize(src_surface);
- gfx::Size dst_size = GetSize(dst_surface);
-
- if (src_size.IsEmpty() || dst_size.IsEmpty())
- return false;
-
- HRESULT hr = S_OK;
- // Set up intermediate buffers needed for downsampling.
- const int resample_count =
- GetResampleCount(src_subrect, dst_size, src_size);
- base::win::ScopedComPtr<IDirect3DSurface9> temp_buffer[2];
- const gfx::Size half_size =
- GetHalfSizeNoLessThan(src_subrect.size(), dst_size);
- if (resample_count > 1) {
- TRACE_EVENT0("gpu", "CreateTemporarySurface");
- if (!d3d_utils::CreateTemporaryLockableSurface(device(),
- half_size,
- temp_buffer[0].Receive()))
- return false;
- }
- if (resample_count > 2) {
- TRACE_EVENT0("gpu", "CreateTemporarySurface");
- const gfx::Size quarter_size = GetHalfSizeNoLessThan(half_size, dst_size);
- if (!d3d_utils::CreateTemporaryLockableSurface(device(),
- quarter_size,
- temp_buffer[1].Receive()))
- return false;
- }
-
- // Repeat downsampling the surface until its size becomes identical to
- // |dst_size|. We keep the factor of each downsampling no more than two
- // because using a factor more than two can introduce aliasing.
- RECT read_rect = src_subrect.ToRECT();
- gfx::Size write_size = half_size;
- int read_buffer_index = 1;
- int write_buffer_index = 0;
- for (int i = 0; i < resample_count; ++i) {
- TRACE_EVENT0("gpu", "StretchRect");
- IDirect3DSurface9* read_buffer =
- (i == 0) ? src_surface : temp_buffer[read_buffer_index];
- IDirect3DSurface9* write_buffer =
- (i == resample_count - 1) ? dst_surface :
- temp_buffer[write_buffer_index];
- RECT write_rect = gfx::Rect(write_size).ToRECT();
- hr = device()->StretchRect(read_buffer,
- &read_rect,
- write_buffer,
- &write_rect,
- D3DTEXF_LINEAR);
-
- if (FAILED(hr))
- return false;
- read_rect = write_rect;
- write_size = GetHalfSizeNoLessThan(write_size, dst_size);
- std::swap(read_buffer_index, write_buffer_index);
- }
-
- return true;
-}
-
-IDirect3DDevice9* AcceleratedSurfaceTransformer::device() {
- return device_;
-}
-
-bool AcceleratedSurfaceTransformer::SetShaderCombo(ShaderCombo combo) {
- HRESULT hr = device()->SetVertexShader(vertex_shaders_[combo]);
- if (!SUCCEEDED(hr))
- return false;
- hr = device()->SetPixelShader(pixel_shaders_[combo]);
- if (!SUCCEEDED(hr))
- return false;
- return true;
-}
\ No newline at end of file diff --git a/ui/surface/accelerated_surface_transformer_win.h b/ui/surface/accelerated_surface_transformer_win.h deleted file mode 100644 index e01804a..0000000 --- a/ui/surface/accelerated_surface_transformer_win.h +++ /dev/null @@ -1,81 +0,0 @@ -// Copyright (c) 2012 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef UI_SURFACE_ACCELERATED_SURFACE_TRANSFORMER_WIN_H_
-#define UI_SURFACE_ACCELERATED_SURFACE_TRANSFORMER_WIN_H_
-
-#include <d3d9.h>
-
-#include "base/memory/ref_counted.h"
-#include "base/single_thread_task_runner.h"
-#include "base/synchronization/lock.h"
-#include "base/synchronization/waitable_event.h"
-#include "base/win/scoped_comptr.h"
-#include "ui/gfx/native_widget_types.h"
-#include "ui/gfx/size.h"
-#include "ui/surface/surface_export.h"
-
-namespace gfx {
-class Size;
-class Rect;
-} // namespace gfx
-
-// Provides useful image filtering operations that are implemented
-// efficiently on DirectX9-class hardware using fragment programs.
-class SURFACE_EXPORT AcceleratedSurfaceTransformer {
- public:
- // Constructs an uninitialized surface transformer. Call Init() before
- // using the resulting object.
- AcceleratedSurfaceTransformer();
-
- // Init() initializes the transformer to operate on a device. This must be
- // called before any other method of this class, and it must be called
- // again after ReleaseAll() or DetachAll() before the class is used.
- //
- // Returns true if successful.
- bool Init(IDirect3DDevice9* device);
-
- // ReleaseAll() releases all direct3d resource references.
- void ReleaseAll();
-
- // DetachAll() leaks all direct3d resource references. This exists in order to
- // work around particular driver bugs, and should only be called at shutdown.
- // TODO(ncarter): Update the leak expectations before checkin.
- void DetachAll();
-
- // Draw a textured quad to a surface, flipping orientation in the y direction.
- bool CopyInverted(
- IDirect3DTexture9* src_texture,
- IDirect3DSurface9* dst_surface,
- const gfx::Size& dst_size);
-
- // Resize a surface using repeated bilinear interpolation.
- bool ResizeBilinear(
- IDirect3DSurface9* src_surface,
- const gfx::Rect& src_subrect,
- IDirect3DSurface9* dst_surface);
-
- private:
- enum ShaderCombo {
- SIMPLE_TEXTURE,
- NUM_SHADERS
- };
-
- // Set the active vertex and pixel shader combination.
- bool SetShaderCombo(ShaderCombo combo);
-
- // Intitializes a vertex and pixel shader combination from compiled bytecode.
- bool InitShaderCombo(const BYTE vertex_shader_instructions[],
- const BYTE pixel_shader_instructions[],
- ShaderCombo shader_combo_name);
-
- IDirect3DDevice9* device();
-
- base::win::ScopedComPtr<IDirect3DDevice9> device_;
- base::win::ScopedComPtr<IDirect3DVertexShader9> vertex_shaders_[NUM_SHADERS];
- base::win::ScopedComPtr<IDirect3DPixelShader9> pixel_shaders_[NUM_SHADERS];
- DISALLOW_COPY_AND_ASSIGN(AcceleratedSurfaceTransformer);
-};
-
-#endif // UI_SURFACE_ACCELERATED_SURFACE_TRANSFORMER_WIN_H_
\ No newline at end of file diff --git a/ui/surface/accelerated_surface_transformer_win_unittest.cc b/ui/surface/accelerated_surface_transformer_win_unittest.cc deleted file mode 100644 index 0e8fed6..0000000 --- a/ui/surface/accelerated_surface_transformer_win_unittest.cc +++ /dev/null @@ -1,525 +0,0 @@ -// Copyright (c) 2010 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include <d3d9.h> -#include <random> - -#include "base/basictypes.h" -#include "base/hash.h" -#include "base/scoped_native_library.h" -#include "base/stringprintf.h" -#include "base/win/scoped_comptr.h" -#include "base/win/windows_version.h" -#include "testing/gtest/include/gtest/gtest-param-test.h" -#include "testing/gtest/include/gtest/gtest.h" -#include "ui/gfx/rect.h" -#include "ui/surface/accelerated_surface_transformer_win.h" -#include "ui/surface/accelerated_surface_win.h" -#include "ui/surface/d3d9_utils_win.h" - -namespace d3d_utils = ui_surface_d3d9_utils; - -using base::win::ScopedComPtr; -using std::uniform_int_distribution; - -// Provides a reference rasterizer (all rendering done by software emulation) -// Direct3D device, for use by unit tests. -// -// This class is parameterized so that it runs only on Vista+. See -// WindowsVersionIfVistaOrBetter() for details on this works. -class AcceleratedSurfaceTransformerTest : public testing::TestWithParam<int> { - public: - AcceleratedSurfaceTransformerTest() {}; - - IDirect3DDevice9Ex* device() { return device_.get(); } - - virtual void SetUp() { - if (!d3d_module_.is_valid()) { - if (!d3d_utils::LoadD3D9(&d3d_module_)) { - GTEST_FAIL() << "Could not load d3d9.dll"; - return; - } - } - if (!d3d_utils::CreateDevice(d3d_module_, - D3DDEVTYPE_HAL, - D3DPRESENT_INTERVAL_IMMEDIATE, - device_.Receive())) { - GTEST_FAIL() << "Could not create Direct3D device."; - return; - } - - SeedRandom("default"); - } - - virtual void TearDown() { - device_ = NULL; - } - - // Gets a human-readable identifier of the graphics hardware being used, - // intended for use inside of SCOPED_TRACE(). - std::string GetAdapterInfo() { - ScopedComPtr<IDirect3D9> d3d; - EXPECT_HRESULT_SUCCEEDED(device()->GetDirect3D(d3d.Receive())); - D3DADAPTER_IDENTIFIER9 info; - EXPECT_HRESULT_SUCCEEDED(d3d->GetAdapterIdentifier(0, 0, &info)); - return StringPrintf("Running on graphics hardware: %s", info.Description); - } - - void SeedRandom(const char* seed) { - rng_.seed(base::Hash(seed)); - random_dword_.reset(); - } - - // Driver workaround: on an Intel GPU (Mobile Intel 965 Express), it seems - // necessary to flush between drawing and locking, for the synchronization - // to behave properly. - void BeforeLockWorkaround() { - EXPECT_HRESULT_SUCCEEDED( - device()->Present(0, 0, 0, 0)); - } - - // Locks and fills a surface with a checkerboard pattern where the colors - // are random but the total image pattern is horizontally and vertically - // symmetric. - void FillSymmetricRandomCheckerboard( - IDirect3DSurface9* lockable_surface, - const gfx::Size& size, - int checker_square_size) { - - D3DLOCKED_RECT locked_rect; - ASSERT_HRESULT_SUCCEEDED( - lockable_surface->LockRect(&locked_rect, NULL, D3DLOCK_DISCARD)); - DWORD* surface = reinterpret_cast<DWORD*>(locked_rect.pBits); - ASSERT_EQ(0, locked_rect.Pitch % sizeof(DWORD)); - int pitch = locked_rect.Pitch / sizeof(DWORD); - - for (int y = 0; y <= size.height() / 2; y += checker_square_size) { - for (int x = 0; x <= size.width() / 2; x += checker_square_size) { - DWORD color = RandomColor(); - int y_limit = std::min(size.height() / 2, y + checker_square_size - 1); - int x_limit = std::min(size.width() / 2, x + checker_square_size - 1); - for (int y_lo = y; y_lo <= y_limit; y_lo++) { - for (int x_lo = x; x_lo <= x_limit; x_lo++) { - int y_hi = size.height() - 1 - y_lo; - int x_hi = size.width() - 1 - x_lo; - surface[x_lo + y_lo*pitch] = color; - surface[x_lo + y_hi*pitch] = color; - surface[x_hi + y_lo*pitch] = color; - surface[x_hi + y_hi*pitch] = color; - } - } - } - } - - lockable_surface->UnlockRect(); - } - - void FillRandomCheckerboard( - IDirect3DSurface9* lockable_surface, - const gfx::Size& size, - int checker_square_size) { - - D3DLOCKED_RECT locked_rect; - ASSERT_HRESULT_SUCCEEDED( - lockable_surface->LockRect(&locked_rect, NULL, D3DLOCK_DISCARD)); - DWORD* surface = reinterpret_cast<DWORD*>(locked_rect.pBits); - ASSERT_EQ(0, locked_rect.Pitch % sizeof(DWORD)); - int pitch = locked_rect.Pitch / sizeof(DWORD); - - for (int y = 0; y <= size.height(); y += checker_square_size) { - for (int x = 0; x <= size.width(); x += checker_square_size) { - DWORD color = RandomColor(); - int y_limit = std::min(size.height(), y + checker_square_size); - int x_limit = std::min(size.width(), x + checker_square_size); - for (int square_y = y; square_y < y_limit; square_y++) { - for (int square_x = x; square_x < x_limit; square_x++) { - surface[square_x + square_y*pitch] = color; - } - } - } - } - - lockable_surface->UnlockRect(); - } - - // Approximate color-equality check. Allows for some rounding error. - bool AssertSameColor(DWORD color_a, DWORD color_b) { - if (color_a == color_b) - return true; - uint8* a = reinterpret_cast<uint8*>(&color_a); - uint8* b = reinterpret_cast<uint8*>(&color_b); - int max_error = 0; - for (int i = 0; i < 4; i++) - max_error = std::max(max_error, - std::abs(static_cast<int>(a[i]) - b[i])); - - if (max_error <= kAbsoluteColorErrorTolerance) - return true; - - std::string expected_color = - StringPrintf("%3d, %3d, %3d, %3d", a[0], a[1], a[2], a[3]); - std::string actual_color = - StringPrintf("%3d, %3d, %3d, %3d", b[0], b[1], b[2], b[3]); - EXPECT_EQ(expected_color, actual_color) - << "Componentwise color difference was " - << max_error << "; max allowed is " << kAbsoluteColorErrorTolerance; - - return false; - } - - // Asserts that an image is symmetric with respect to itself: both - // horizontally and vertically, within the tolerance of AssertSameColor. - void AssertSymmetry(IDirect3DSurface9* lockable_surface, - const gfx::Size& size) { - BeforeLockWorkaround(); - - D3DLOCKED_RECT locked_rect; - ASSERT_HRESULT_SUCCEEDED( - lockable_surface->LockRect(&locked_rect, NULL, D3DLOCK_READONLY)); - ASSERT_EQ(0, locked_rect.Pitch % sizeof(DWORD)); - int pitch = locked_rect.Pitch / sizeof(DWORD); - DWORD* surface = reinterpret_cast<DWORD*>(locked_rect.pBits); - for (int y_lo = 0; y_lo < size.height() / 2; y_lo++) { - int y_hi = size.height() - 1 - y_lo; - for (int x_lo = 0; x_lo < size.width() / 2; x_lo++) { - int x_hi = size.width() - 1 - x_lo; - if (!AssertSameColor(surface[x_lo + y_lo*pitch], - surface[x_hi + y_lo*pitch])) { - lockable_surface->UnlockRect(); - GTEST_FAIL() << "Pixels (" << x_lo << ", " << y_lo << ") vs. " - << "(" << x_hi << ", " << y_lo << ")"; - } - if (!AssertSameColor(surface[x_hi + y_lo*pitch], - surface[x_hi + y_hi*pitch])) { - lockable_surface->UnlockRect(); - GTEST_FAIL() << "Pixels (" << x_hi << ", " << y_lo << ") vs. " - << "(" << x_hi << ", " << y_hi << ")"; - } - if (!AssertSameColor(surface[x_hi + y_hi*pitch], - surface[x_lo + y_hi*pitch])) { - lockable_surface->UnlockRect(); - GTEST_FAIL() << "Pixels (" << x_hi << ", " << y_hi << ") vs. " - << "(" << x_lo << ", " << y_hi << ")"; - } - } - } - lockable_surface->UnlockRect(); - } - - // Asserts that the actual image is a bit-identical, vertically mirrored - // copy of the expected image. - void AssertIsInvertedCopy(const gfx::Size& size, - IDirect3DSurface9* expected, - IDirect3DSurface9* actual) { - BeforeLockWorkaround(); - - D3DLOCKED_RECT locked_expected, locked_actual; - ASSERT_HRESULT_SUCCEEDED( - expected->LockRect(&locked_expected, NULL, D3DLOCK_READONLY)); - ASSERT_HRESULT_SUCCEEDED( - actual->LockRect(&locked_actual, NULL, D3DLOCK_READONLY)); - ASSERT_EQ(0, locked_expected.Pitch % sizeof(DWORD)); - int pitch = locked_expected.Pitch / sizeof(DWORD); - DWORD* expected_image = reinterpret_cast<DWORD*>(locked_expected.pBits); - DWORD* actual_image = reinterpret_cast<DWORD*>(locked_actual.pBits); - for (int y = 0; y < size.height(); y++) { - int y_actual = size.height() - 1 - y; - for (int x = 0; x < size.width(); ++x) - if (!AssertSameColor(expected_image[y*pitch + x], - actual_image[y_actual*pitch + x])) { - expected->UnlockRect(); - actual->UnlockRect(); - GTEST_FAIL() << "Pixels (" << x << ", " << y << ") vs. " - << "(" << x << ", " << y_actual << ")"; - } - } - expected->UnlockRect(); - actual->UnlockRect(); - } - - protected: - static const int kAbsoluteColorErrorTolerance = 5; - - DWORD RandomColor() { - return random_dword_(rng_); - } - - void DoResizeBilinearTest(AcceleratedSurfaceTransformer* gpu_ops, - const gfx::Size& src_size, - const gfx::Size& dst_size, - int checkerboard_size) { - - SCOPED_TRACE( - StringPrintf("Resizing %dx%d -> %dx%d at checkerboard size of %d", - src_size.width(), src_size.height(), - dst_size.width(), dst_size.height(), - checkerboard_size)); - - base::win::ScopedComPtr<IDirect3DSurface9> src, dst; - ASSERT_TRUE(d3d_utils::CreateTemporaryLockableSurface( - device(), src_size, src.Receive())) - << "Could not create src render target"; - ASSERT_TRUE(d3d_utils::CreateTemporaryLockableSurface( - device(), dst_size, dst.Receive())) - << "Could not create dst render target"; - - FillSymmetricRandomCheckerboard(src, src_size, checkerboard_size); - - ASSERT_TRUE(gpu_ops->ResizeBilinear(src, gfx::Rect(src_size), dst)); - - AssertSymmetry(dst, dst_size); - } - - void DoCopyInvertedTest(AcceleratedSurfaceTransformer* gpu_ops, - const gfx::Size& size) { - - SCOPED_TRACE( - StringPrintf("CopyInverted @ %dx%d", size.width(), size.height())); - - base::win::ScopedComPtr<IDirect3DSurface9> checkerboard, src, dst; - base::win::ScopedComPtr<IDirect3DTexture9> src_texture; - ASSERT_TRUE(d3d_utils::CreateTemporaryLockableSurface(device(), size, - checkerboard.Receive())) << "Could not create src render target";; - ASSERT_TRUE(d3d_utils::CreateTemporaryRenderTargetTexture(device(), size, - src_texture.Receive(), src.Receive())) - << "Could not create src texture."; - ASSERT_TRUE(d3d_utils::CreateTemporaryLockableSurface(device(), size, - dst.Receive())) << "Could not create dst render target."; - - FillRandomCheckerboard(checkerboard, size, 1); - ASSERT_HRESULT_SUCCEEDED( - device()->StretchRect(checkerboard, NULL, src, NULL, D3DTEXF_NONE)); - ASSERT_TRUE(gpu_ops->CopyInverted(src_texture, dst, size)); - AssertIsInvertedCopy(size, checkerboard, dst); - } - - uniform_int_distribution<DWORD> random_dword_; - std::mt19937 rng_; - base::ScopedNativeLibrary d3d_module_; - base::win::ScopedComPtr<IDirect3DDevice9Ex> device_; -}; - -// Fails on some bots because Direct3D isn't allowed. -TEST_P(AcceleratedSurfaceTransformerTest, FLAKY_Init) { - SCOPED_TRACE(GetAdapterInfo()); - AcceleratedSurfaceTransformer gpu_ops; - ASSERT_TRUE(gpu_ops.Init(device())); -}; - -// Fails on some bots because Direct3D isn't allowed. -TEST_P(AcceleratedSurfaceTransformerTest, FLAKY_TestConsistentRandom) { - // This behavior should be the same for every execution on every machine. - // Otherwise tests might be flaky and impossible to debug. - SeedRandom("AcceleratedSurfaceTransformerTest.TestConsistentRandom"); - ASSERT_EQ(2922058934, RandomColor()); - - SeedRandom("AcceleratedSurfaceTransformerTest.TestConsistentRandom"); - ASSERT_EQ(2922058934, RandomColor()); - ASSERT_EQ(4050239976, RandomColor()); - - SeedRandom("DifferentSeed"); - ASSERT_EQ(3904108833, RandomColor()); -} - -// Fails on some bots because Direct3D isn't allowed. -TEST_P(AcceleratedSurfaceTransformerTest, FLAKY_CopyInverted) { - // This behavior should be the same for every execution on every machine. - // Otherwise tests might be flaky and impossible to debug. - SCOPED_TRACE(GetAdapterInfo()); - SeedRandom("CopyInverted"); - - AcceleratedSurfaceTransformer t; - ASSERT_TRUE(t.Init(device())); - - uniform_int_distribution<int> size(1, 512); - - for (int i = 0; i < 100; ++i) { - ASSERT_NO_FATAL_FAILURE( - DoCopyInvertedTest(&t, gfx::Size(size(rng_), size(rng_)))) - << "At iteration " << i; - } -} - - -// Fails on some bots because Direct3D isn't allowed. -// Fails on other bots because of ResizeBilinear symmetry failures. -// Should pass, at least, on NVIDIA Quadro 600. -TEST_P(AcceleratedSurfaceTransformerTest, FLAKY_MixedOperations) { - SCOPED_TRACE(GetAdapterInfo()); - SeedRandom("MixedOperations"); - - AcceleratedSurfaceTransformer t; - ASSERT_TRUE(t.Init(device())); - - ASSERT_NO_FATAL_FAILURE( - DoResizeBilinearTest(&t, gfx::Size(256, 256), gfx::Size(255, 255), 1)); - ASSERT_NO_FATAL_FAILURE( - DoResizeBilinearTest(&t, gfx::Size(256, 256), gfx::Size(255, 255), 2)); - ASSERT_NO_FATAL_FAILURE( - DoCopyInvertedTest(&t, gfx::Size(20, 107))); - ASSERT_NO_FATAL_FAILURE( - DoResizeBilinearTest(&t, gfx::Size(256, 256), gfx::Size(255, 255), 5)); - ASSERT_NO_FATAL_FAILURE( - DoResizeBilinearTest(&t, gfx::Size(256, 256), gfx::Size(64, 64), 5)); - ASSERT_NO_FATAL_FAILURE( - DoResizeBilinearTest(&t, gfx::Size(255, 255), gfx::Size(3, 3), 1)); - ASSERT_NO_FATAL_FAILURE( - DoCopyInvertedTest(&t, gfx::Size(1412, 124))); - ASSERT_NO_FATAL_FAILURE( - DoResizeBilinearTest(&t, gfx::Size(255, 255), gfx::Size(257, 257), 1)); - ASSERT_NO_FATAL_FAILURE( - DoResizeBilinearTest(&t, gfx::Size(255, 255), gfx::Size(257, 257), 2)); - - ASSERT_NO_FATAL_FAILURE( - DoCopyInvertedTest(&t, gfx::Size(1512, 7))); - ASSERT_NO_FATAL_FAILURE( - DoResizeBilinearTest(&t, gfx::Size(255, 255), gfx::Size(257, 257), 5)); - ASSERT_NO_FATAL_FAILURE( - DoResizeBilinearTest(&t, gfx::Size(150, 256), gfx::Size(126, 256), 8)); - ASSERT_NO_FATAL_FAILURE( - DoCopyInvertedTest(&t, gfx::Size(1521, 3))); - ASSERT_NO_FATAL_FAILURE( - DoResizeBilinearTest(&t, gfx::Size(150, 256), gfx::Size(126, 256), 1)); - ASSERT_NO_FATAL_FAILURE( - DoCopyInvertedTest(&t, gfx::Size(33, 712))); - ASSERT_NO_FATAL_FAILURE( - DoResizeBilinearTest(&t, gfx::Size(150, 256), gfx::Size(126, 8), 8)); - ASSERT_NO_FATAL_FAILURE( - DoCopyInvertedTest(&t, gfx::Size(33, 2))); - ASSERT_NO_FATAL_FAILURE( - DoResizeBilinearTest(&t, gfx::Size(200, 256), gfx::Size(126, 8), 8)); -} - -// Tests ResizeBilinear with 16K wide/hight src and dst surfaces. -// -// Fails on some bots because Direct3D isn't allowed. -// Should pass, at least, on NVIDIA Quadro 600. -TEST_P(AcceleratedSurfaceTransformerTest, FLAKY_LargeSurfaces) { - SCOPED_TRACE(GetAdapterInfo()); - SeedRandom("LargeSurfaces"); - - AcceleratedSurfaceTransformer gpu_ops; - ASSERT_TRUE(gpu_ops.Init(device())); - - D3DCAPS9 caps; - ASSERT_HRESULT_SUCCEEDED( - device()->GetDeviceCaps(&caps)); - - SCOPED_TRACE(StringPrintf("max texture size: %dx%d, max texture aspect: %d", - caps.MaxTextureWidth, caps.MaxTextureHeight, caps.MaxTextureAspectRatio)); - - const int w = caps.MaxTextureWidth; - const int h = caps.MaxTextureHeight; - const int lo = 256; - - ASSERT_NO_FATAL_FAILURE( - DoResizeBilinearTest(&gpu_ops, gfx::Size(w, lo), gfx::Size(lo, lo), 1)); - ASSERT_NO_FATAL_FAILURE( - DoResizeBilinearTest(&gpu_ops, gfx::Size(lo, h), gfx::Size(lo, lo), 1)); - ASSERT_NO_FATAL_FAILURE( - DoResizeBilinearTest(&gpu_ops, gfx::Size(lo, lo), gfx::Size(w, lo), lo)); - ASSERT_NO_FATAL_FAILURE( - DoResizeBilinearTest(&gpu_ops, gfx::Size(lo, lo), gfx::Size(lo, h), lo)); - ASSERT_NO_FATAL_FAILURE( - DoCopyInvertedTest(&gpu_ops, gfx::Size(w, lo))); - ASSERT_NO_FATAL_FAILURE( - DoCopyInvertedTest(&gpu_ops, gfx::Size(lo, h))); -} - -// Exercises ResizeBilinear with random minification cases where the -// aspect ratio does not change. -// -// Fails on some bots because Direct3D isn't allowed. -// Fails on other bots because of StretchRect symmetry failures. -// Should pass, at least, on NVIDIA Quadro 600. -TEST_P(AcceleratedSurfaceTransformerTest, FLAKY_MinifyUniform) { - SCOPED_TRACE(GetAdapterInfo()); - SeedRandom("MinifyUniform"); - - AcceleratedSurfaceTransformer gpu_ops; - ASSERT_TRUE(gpu_ops.Init(device())); - - int dims[] = { 21, 63, 64, 65, 99, 127, 128, 129, 192, 255, 256, 257}; - int checkerboards[] = {1, 2, 3, 9}; - uniform_int_distribution<int> dim(0, arraysize(dims) - 1); - uniform_int_distribution<int> checkerboard(0, arraysize(checkerboards) - 1); - - for (int i = 0; i < 300; i++) { - // Widths are picked so that dst is smaller than src. - int dst_width = dims[dim(rng_)]; - int src_width = dims[dim(rng_)]; - if (src_width < dst_width) - std::swap(dst_width, src_width); - - // src_width is picked to preserve aspect ratio. - int dst_height = dims[dim(rng_)]; - int src_height = static_cast<int>( - static_cast<int64>(src_width) * dst_height / dst_width); - - int checkerboard_size = checkerboards[checkerboard(rng_)]; - - ASSERT_NO_FATAL_FAILURE( - DoResizeBilinearTest(&gpu_ops, - gfx::Size(src_width, src_height), // Src size (larger) - gfx::Size(dst_width, dst_height), // Dst size (smaller) - checkerboard_size)) << "Failed on iteration " << i; - } -}; - -// Exercises ResizeBilinear with random magnification cases where the -// aspect ratio does not change. -// -// This test relies on an assertion that resizing preserves symmetry in the -// image, but for the current implementation of ResizeBilinear, this does not -// seem to be true (fails on NVIDIA Quadro 600; passes on -// Intel Mobile 965 Express) -TEST_P(AcceleratedSurfaceTransformerTest, FLAKY_MagnifyUniform) { - SCOPED_TRACE(GetAdapterInfo()); - SeedRandom("MagnifyUniform"); - - AcceleratedSurfaceTransformer gpu_ops; - ASSERT_TRUE(gpu_ops.Init(device())); - - int dims[] = {63, 64, 65, 99, 127, 128, 129, 192, 255, 256, 257}; - int checkerboards[] = {1, 2, 3, 9}; - uniform_int_distribution<int> dim(0, arraysize(dims) - 1); - uniform_int_distribution<int> checkerboard(0, arraysize(checkerboards) - 1); - - for (int i = 0; i < 50; i++) { - // Widths are picked so that b is smaller than a. - int dst_width = dims[dim(rng_)]; - int src_width = dims[dim(rng_)]; - if (dst_width < src_width) - std::swap(src_width, dst_width); - - int dst_height = dims[dim(rng_)]; - int src_height = static_cast<int>( - static_cast<int64>(src_width) * dst_height / dst_width); - - int checkerboard_size = checkerboards[checkerboard(rng_)]; - - ASSERT_NO_FATAL_FAILURE( - DoResizeBilinearTest(&gpu_ops, - gfx::Size(src_width, src_height), // Src size (smaller) - gfx::Size(dst_width, dst_height), // Dst size (larger) - checkerboard_size)) << "Failed on iteration " << i; - } -}; - -namespace { - -// Used to suppress test on Windows versions prior to Vista. -std::vector<int> WindowsVersionIfVistaOrBetter() { - std::vector<int> result; - if (base::win::GetVersion() >= base::win::VERSION_VISTA) { - result.push_back(base::win::GetVersion()); - } - return result; -} - -} // namespace - -INSTANTIATE_TEST_CASE_P(VistaAndUp, - AcceleratedSurfaceTransformerTest, - ::testing::ValuesIn(WindowsVersionIfVistaOrBetter())); diff --git a/ui/surface/accelerated_surface_win.cc b/ui/surface/accelerated_surface_win.cc index 0ac8f1c..0fa247d7 100644 --- a/ui/surface/accelerated_surface_win.cc +++ b/ui/surface/accelerated_surface_win.cc @@ -8,6 +8,7 @@ #include <windows.h> #include <algorithm> +#include "accelerated_surface_win_hlsl_compiled.h" #include "base/bind.h" #include "base/bind_helpers.h" #include "base/callback.h" @@ -29,15 +30,33 @@ #include "ui/base/win/hwnd_util.h" #include "ui/gfx/rect.h" #include "ui/gl/gl_switches.h" -#include "ui/surface/accelerated_surface_transformer_win.h" -#include "ui/surface/d3d9_utils_win.h" -namespace d3d_utils = ui_surface_d3d9_utils; + +using ui_surface::AcceleratedSurfaceWinHLSL::kVsOneTexture; +using ui_surface::AcceleratedSurfaceWinHLSL::kPsOneTexture; + namespace { +typedef HRESULT (WINAPI *Direct3DCreate9ExFunc)(UINT sdk_version, + IDirect3D9Ex **d3d); + +const wchar_t kD3D9ModuleName[] = L"d3d9.dll"; +const char kCreate3D9DeviceExName[] = "Direct3DCreate9Ex"; + const char kUseOcclusionQuery[] = "use-occlusion-query"; +struct Vertex { + float x, y, z, w; + float u, v; +}; + +const static D3DVERTEXELEMENT9 g_vertexElements[] = { + { 0, 0, D3DDECLTYPE_FLOAT4, 0, D3DDECLUSAGE_POSITION, 0 }, + { 0, 16, D3DDECLTYPE_FLOAT2, 0, D3DDECLUSAGE_TEXCOORD, 0 }, + D3DDECL_END() +}; + UINT GetPresentationInterval() { if (CommandLine::ForCurrentProcess()->HasSwitch(switches::kDisableGpuVsync)) return D3DPRESENT_INTERVAL_IMMEDIATE; @@ -49,6 +68,53 @@ bool UsingOcclusionQuery() { return CommandLine::ForCurrentProcess()->HasSwitch(kUseOcclusionQuery); } +// Calculate the number necessary to transform |src_subrect| into |dst_size| +// by repeating downsampling of the image of |src_subrect| by a factor no more +// than 2. +int GetResampleCount(const gfx::Rect& src_subrect, + const gfx::Size& dst_size, + const gfx::Size& back_buffer_size) { + // At least one copy is required, since the back buffer itself is not + // lockable. + int min_resample_count = 1; + int width_count = 0; + int width = src_subrect.width(); + while (width > dst_size.width()) { + ++width_count; + width >>= 1; + } + int height_count = 0; + int height = src_subrect.height(); + while (height > dst_size.height()) { + ++height_count; + height >>= 1; + } + return std::max(std::max(width_count, height_count), + min_resample_count); +} + +// Returns half the size of |size| no smaller than |min_size|. +gfx::Size GetHalfSizeNoLessThan(const gfx::Size& size, + const gfx::Size& min_size) { + return gfx::Size(std::max(min_size.width(), size.width() / 2), + std::max(min_size.height(), size.height() / 2)); +} + +bool CreateTemporarySurface(IDirect3DDevice9* device, + const gfx::Size& size, + IDirect3DSurface9** surface) { + HRESULT hr = device->CreateRenderTarget( + size.width(), + size.height(), + D3DFMT_A8R8G8B8, + D3DMULTISAMPLE_NONE, + 0, + TRUE, + surface, + NULL); + return SUCCEEDED(hr); +} + } // namespace // A PresentThread is a thread that is dedicated to presenting surfaces to a @@ -60,9 +126,6 @@ class PresentThread : public base::Thread, IDirect3DDevice9Ex* device() { return device_.get(); } IDirect3DQuery9* query() { return query_.get(); } - AcceleratedSurfaceTransformer* surface_transformer() { - return &surface_transformer_; - } void InitDevice(); void ResetDevice(); @@ -78,11 +141,11 @@ class PresentThread : public base::Thread, base::ScopedNativeLibrary d3d_module_; base::win::ScopedComPtr<IDirect3DDevice9Ex> device_; + // This query is used to wait until a certain amount of progress has been // made by the GPU and it is safe for the producer to modify its shared // texture again. base::win::ScopedComPtr<IDirect3DQuery9> query_; - AcceleratedSurfaceTransformer surface_transformer_; DISALLOW_COPY_AND_ASSIGN(PresentThread); }; @@ -135,7 +198,7 @@ void PresentThread::InitDevice() { return; TRACE_EVENT0("gpu", "PresentThread::Init"); - d3d_utils::LoadD3D9(&d3d_module_); + d3d_module_.Reset(base::LoadNativeLibrary(FilePath(kD3D9ModuleName), NULL)); ResetDevice(); } @@ -147,32 +210,92 @@ void PresentThread::ResetDevice() { query_ = NULL; device_ = NULL; - if (!d3d_utils::CreateDevice(d3d_module_, - D3DDEVTYPE_HAL, - GetPresentationInterval(), - device_.Receive())) { + Direct3DCreate9ExFunc create_func = reinterpret_cast<Direct3DCreate9ExFunc>( + d3d_module_.GetFunctionPointer(kCreate3D9DeviceExName)); + if (!create_func) + return; + + base::win::ScopedComPtr<IDirect3D9Ex> d3d; + HRESULT hr = create_func(D3D_SDK_VERSION, d3d.Receive()); + if (FAILED(hr)) + return; + + // Any old window will do to create the device. In practice the window to + // present to is an argument to IDirect3DDevice9::Present. + HWND window = GetShellWindow(); + + D3DPRESENT_PARAMETERS parameters = { 0 }; + parameters.BackBufferWidth = 1; + parameters.BackBufferHeight = 1; + parameters.BackBufferCount = 1; + parameters.BackBufferFormat = D3DFMT_A8R8G8B8; + parameters.hDeviceWindow = window; + parameters.Windowed = TRUE; + parameters.Flags = 0; + parameters.PresentationInterval = GetPresentationInterval(); + parameters.SwapEffect = D3DSWAPEFFECT_COPY; + + hr = d3d->CreateDeviceEx( + D3DADAPTER_DEFAULT, + D3DDEVTYPE_HAL, + window, + D3DCREATE_FPU_PRESERVE | D3DCREATE_SOFTWARE_VERTEXPROCESSING | + D3DCREATE_DISABLE_PSGP_THREADING | D3DCREATE_MULTITHREADED, + ¶meters, + NULL, + device_.Receive()); + if (FAILED(hr)) return; - } if (UsingOcclusionQuery()) { - HRESULT hr = device_->CreateQuery(D3DQUERYTYPE_OCCLUSION, query_.Receive()); + hr = device_->CreateQuery(D3DQUERYTYPE_OCCLUSION, query_.Receive()); if (FAILED(hr)) { device_ = NULL; return; } } else { - HRESULT hr = device_->CreateQuery(D3DQUERYTYPE_EVENT, query_.Receive()); + hr = device_->CreateQuery(D3DQUERYTYPE_EVENT, query_.Receive()); if (FAILED(hr)) { device_ = NULL; return; } } - if (!surface_transformer_.Init(device_)) { + base::win::ScopedComPtr<IDirect3DVertexShader9> vertex_shader; + hr = device_->CreateVertexShader( + reinterpret_cast<const DWORD*>(kVsOneTexture), + vertex_shader.Receive()); + if (FAILED(hr)) { + device_ = NULL; query_ = NULL; + return; + } + + device_->SetVertexShader(vertex_shader); + + base::win::ScopedComPtr<IDirect3DPixelShader9> pixel_shader; + hr = device_->CreatePixelShader( + reinterpret_cast<const DWORD*>(kPsOneTexture), + pixel_shader.Receive()); + + if (FAILED(hr)) { device_ = NULL; + query_ = NULL; return; } + + device_->SetPixelShader(pixel_shader); + + base::win::ScopedComPtr<IDirect3DVertexDeclaration9> vertex_declaration; + hr = device_->CreateVertexDeclaration(g_vertexElements, + vertex_declaration.Receive()); + if (FAILED(hr)) { + device_ = NULL; + query_ = NULL; + return; + } + + device_->SetVertexDeclaration(vertex_declaration); } void PresentThread::Init() { @@ -182,7 +305,6 @@ void PresentThread::Init() { void PresentThread::CleanUp() { // The D3D device and query are leaked because destroying the associated D3D // query crashes some Intel drivers. - surface_transformer_.DetachAll(); device_.Detach(); query_.Detach(); } @@ -260,7 +382,6 @@ AcceleratedPresenter::AcceleratedPresenter(gfx::PluginWindowHandle window) hidden_(true) { } -// static scoped_refptr<AcceleratedPresenter> AcceleratedPresenter::GetForWindow( gfx::PluginWindowHandle window) { return g_accelerated_presenter_map.Pointer()->GetPresenter(window); @@ -349,9 +470,6 @@ bool AcceleratedPresenter::DoCopyTo(const gfx::Rect& requested_src_subrect, if (!swap_chain_) return false; - AcceleratedSurfaceTransformer* gpu_ops = - present_thread_->surface_transformer(); - base::win::ScopedComPtr<IDirect3DSurface9> back_buffer; HRESULT hr = swap_chain_->GetBackBuffer(0, D3DBACKBUFFER_TYPE_MONO, @@ -372,23 +490,65 @@ bool AcceleratedPresenter::DoCopyTo(const gfx::Rect& requested_src_subrect, // the requested src subset. Clip to the actual back buffer. gfx::Rect src_subrect = requested_src_subrect; src_subrect.Intersect(gfx::Rect(back_buffer_size)); + + // Set up intermediate buffers needed for downsampling. + const int resample_count = + GetResampleCount(src_subrect, dst_size, back_buffer_size); base::win::ScopedComPtr<IDirect3DSurface9> final_surface; - { - TRACE_EVENT0("gpu", "CreateTemporaryLockableSurface"); - if (!d3d_utils::CreateTemporaryLockableSurface(present_thread_->device(), - dst_size, - final_surface.Receive())) { + base::win::ScopedComPtr<IDirect3DSurface9> temp_buffer[2]; + if (resample_count == 0) + final_surface = back_buffer; + if (resample_count > 0) { + TRACE_EVENT0("gpu", "CreateTemporarySurface"); + if (!CreateTemporarySurface(present_thread_->device(), + dst_size, + final_surface.Receive())) return false; - } } - - { - // Let the surface transformer start the resize into |final_surface|. - TRACE_EVENT0("gpu", "ResizeBilinear"); - if (!gpu_ops->ResizeBilinear(back_buffer, src_subrect, final_surface)) + const gfx::Size half_size = + GetHalfSizeNoLessThan(src_subrect.size(), dst_size); + if (resample_count > 1) { + TRACE_EVENT0("gpu", "CreateTemporarySurface"); + if (!CreateTemporarySurface(present_thread_->device(), + half_size, + temp_buffer[0].Receive())) + return false; + } + if (resample_count > 2) { + TRACE_EVENT0("gpu", "CreateTemporarySurface"); + const gfx::Size quarter_size = GetHalfSizeNoLessThan(half_size, dst_size); + if (!CreateTemporarySurface(present_thread_->device(), + quarter_size, + temp_buffer[1].Receive())) return false; } + // Repeat downsampling the surface until its size becomes identical to + // |dst_size|. We keep the factor of each downsampling no more than two + // because using a factor more than two can introduce aliasing. + RECT read_rect = src_subrect.ToRECT(); + gfx::Size write_size = half_size; + int read_buffer_index = 1; + int write_buffer_index = 0; + for (int i = 0; i < resample_count; ++i) { + TRACE_EVENT0("gpu", "StretchRect"); + base::win::ScopedComPtr<IDirect3DSurface9> read_buffer = + (i == 0) ? back_buffer : temp_buffer[read_buffer_index]; + base::win::ScopedComPtr<IDirect3DSurface9> write_buffer = + (i == resample_count - 1) ? final_surface : + temp_buffer[write_buffer_index]; + RECT write_rect = gfx::Rect(write_size).ToRECT(); + hr = present_thread_->device()->StretchRect(read_buffer, + &read_rect, + write_buffer, + &write_rect, + D3DTEXF_LINEAR); + if (FAILED(hr)) + return false; + read_rect = write_rect; + write_size = GetHalfSizeNoLessThan(write_size, dst_size); + std::swap(read_buffer_index, write_buffer_index); + } D3DLOCKED_RECT locked_rect; // Empirical evidence seems to suggest that LockRect and memcpy are faster @@ -556,13 +716,18 @@ void AcceleratedPresenter::DoPresentAndAcknowledge( } if (!source_texture_.get()) { - TRACE_EVENT0("gpu", "OpenSharedTexture"); - if (!d3d_utils::OpenSharedTexture(present_thread_->device(), - surface_handle, - size, - source_texture_.Receive())) { + TRACE_EVENT0("gpu", "CreateTexture"); + HANDLE handle = reinterpret_cast<HANDLE>(surface_handle); + hr = present_thread_->device()->CreateTexture(size.width(), + size.height(), + 1, + D3DUSAGE_RENDERTARGET, + D3DFMT_A8R8G8B8, + D3DPOOL_DEFAULT, + source_texture_.Receive(), + &handle); + if (FAILED(hr)) return; - } } base::win::ScopedComPtr<IDirect3DSurface9> source_surface; @@ -589,15 +754,44 @@ void AcceleratedPresenter::DoPresentAndAcknowledge( { TRACE_EVENT0("gpu", "Copy"); + // Use a simple pixel / vertex shader pair to render a quad that flips the + // source texture on the vertical axis. + IDirect3DSurface9 *default_render_target = NULL; + present_thread_->device()->GetRenderTarget(0, &default_render_target); + + present_thread_->device()->SetRenderTarget(0, dest_surface); + present_thread_->device()->SetTexture(0, source_texture_); + + D3DVIEWPORT9 viewport = { + 0, 0, + size.width(), size.height(), + 0, 1 + }; + present_thread_->device()->SetViewport(&viewport); + + float halfPixelX = -1.0f / size.width(); + float halfPixelY = 1.0f / size.height(); + Vertex vertices[] = { + { halfPixelX - 1, halfPixelY + 1, 0.5f, 1, 0, 1 }, + { halfPixelX + 1, halfPixelY + 1, 0.5f, 1, 1, 1 }, + { halfPixelX + 1, halfPixelY - 1, 0.5f, 1, 1, 0 }, + { halfPixelX - 1, halfPixelY - 1, 0.5f, 1, 0, 0 } + }; + if (UsingOcclusionQuery()) { present_thread_->query()->Issue(D3DISSUE_BEGIN); } - // Copy while flipping the source texture on the vertical axis. - bool result = present_thread_->surface_transformer()->CopyInverted( - source_texture_, dest_surface, size); - if (!result) - return; + present_thread_->device()->BeginScene(); + present_thread_->device()->DrawPrimitiveUP(D3DPT_TRIANGLEFAN, + 2, + vertices, + sizeof(vertices[0])); + present_thread_->device()->EndScene(); + + present_thread_->device()->SetTexture(0, NULL); + present_thread_->device()->SetRenderTarget(0, default_render_target); + default_render_target->Release(); } hr = present_thread_->query()->Issue(D3DISSUE_END); diff --git a/ui/surface/accelerated_surface_transformer_win.hlsl b/ui/surface/accelerated_surface_win.hlsl index 0bd6fda..bc87dee 100644 --- a/ui/surface/accelerated_surface_transformer_win.hlsl +++ b/ui/surface/accelerated_surface_win.hlsl @@ -3,7 +3,7 @@ // found in the LICENSE file. // @gyp_namespace(ui_surface) -// Compiles into C++ as 'accelerated_surface_transformer_win_hlsl_compiled.h' +// Compiles into C++ as 'accelerated_surface_win_hlsl_compiled.h' struct Vertex { float4 position : POSITION; @@ -25,4 +25,4 @@ Vertex vsOneTexture(Vertex input) { // Samples a texture at the given texture coordinate and returns the result. float4 psOneTexture(float2 texCoord : TEXCOORD0) : COLOR0 { return tex2D(s, texCoord); -}; +};
\ No newline at end of file diff --git a/ui/surface/d3d9_utils_win.cc b/ui/surface/d3d9_utils_win.cc deleted file mode 100644 index d5cab8e..0000000 --- a/ui/surface/d3d9_utils_win.cc +++ /dev/null @@ -1,119 +0,0 @@ -// Copyright (c) 2012 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "ui/surface/d3d9_utils_win.h"
-
-#include "base/file_path.h"
-#include "base/scoped_native_library.h"
-#include "base/win/scoped_comptr.h"
-#include "ui/gfx/size.h"
-
-namespace {
-
-const wchar_t kD3D9ModuleName[] = L"d3d9.dll";
-const char kCreate3D9DeviceExName[] = "Direct3DCreate9Ex";
-typedef HRESULT (WINAPI *Direct3DCreate9ExFunc)(UINT sdk_version,
- IDirect3D9Ex **d3d);
-} // namespace
-
-namespace ui_surface_d3d9_utils {
-
-bool LoadD3D9(base::ScopedNativeLibrary* storage) {
- storage->Reset(base::LoadNativeLibrary(FilePath(kD3D9ModuleName), NULL));
- return storage->is_valid();
-}
-
-bool CreateDevice(const base::ScopedNativeLibrary& d3d_module,
- D3DDEVTYPE device_type,
- uint32 presentation_interval,
- IDirect3DDevice9Ex** device) {
-
- Direct3DCreate9ExFunc create_func = reinterpret_cast<Direct3DCreate9ExFunc>(
- d3d_module.GetFunctionPointer(kCreate3D9DeviceExName));
- if (!create_func)
- return false;
-
- base::win::ScopedComPtr<IDirect3D9Ex> d3d;
- HRESULT hr = create_func(D3D_SDK_VERSION, d3d.Receive());
- if (FAILED(hr))
- return false;
-
- // Any old window will do to create the device. In practice the window to
- // present to is an argument to IDirect3DDevice9::Present.
- HWND window = GetShellWindow();
-
- D3DPRESENT_PARAMETERS parameters = { 0 };
- parameters.BackBufferWidth = 1;
- parameters.BackBufferHeight = 1;
- parameters.BackBufferCount = 1;
- parameters.BackBufferFormat = D3DFMT_A8R8G8B8;
- parameters.hDeviceWindow = window;
- parameters.Windowed = TRUE;
- parameters.Flags = 0;
- parameters.PresentationInterval = presentation_interval;
- parameters.SwapEffect = D3DSWAPEFFECT_COPY;
-
- hr = d3d->CreateDeviceEx(
- D3DADAPTER_DEFAULT,
- device_type,
- window,
- D3DCREATE_FPU_PRESERVE | D3DCREATE_SOFTWARE_VERTEXPROCESSING |
- D3DCREATE_DISABLE_PSGP_THREADING | D3DCREATE_MULTITHREADED,
- ¶meters,
- NULL,
- device);
- return SUCCEEDED(hr);
-}
-
-bool OpenSharedTexture(IDirect3DDevice9* device,
- int64 surface_handle,
- const gfx::Size& size,
- IDirect3DTexture9** opened_texture) {
- HANDLE handle = reinterpret_cast<HANDLE>(surface_handle);
- HRESULT hr = device->CreateTexture(size.width(),
- size.height(),
- 1,
- D3DUSAGE_RENDERTARGET,
- D3DFMT_A8R8G8B8,
- D3DPOOL_DEFAULT,
- opened_texture,
- &handle);
- return SUCCEEDED(hr);
-}
-
-bool CreateTemporaryLockableSurface(IDirect3DDevice9* device,
- const gfx::Size& size,
- IDirect3DSurface9** surface) {
- HRESULT hr = device->CreateRenderTarget(
- size.width(),
- size.height(),
- D3DFMT_A8R8G8B8,
- D3DMULTISAMPLE_NONE,
- 0,
- TRUE,
- surface,
- NULL);
- return SUCCEEDED(hr);
-}
-
-bool CreateTemporaryRenderTargetTexture(IDirect3DDevice9* device,
- const gfx::Size& size,
- IDirect3DTexture9** texture,
- IDirect3DSurface9** render_target) {
- HRESULT hr = device->CreateTexture(
- size.width(),
- size.height(),
- 1, // Levels
- D3DUSAGE_RENDERTARGET,
- D3DFMT_A8R8G8B8,
- D3DPOOL_DEFAULT,
- texture,
- NULL);
- if (!SUCCEEDED(hr))
- return false;
- hr = (*texture)->GetSurfaceLevel(0, render_target);
- return SUCCEEDED(hr);
-}
-
-} // namespace ui_surface_d3d9_utils
diff --git a/ui/surface/d3d9_utils_win.h b/ui/surface/d3d9_utils_win.h deleted file mode 100644 index a9554dc..0000000 --- a/ui/surface/d3d9_utils_win.h +++ /dev/null @@ -1,71 +0,0 @@ -// Copyright (c) 2012 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-// Helper functions that Direct3D 9Ex code a little easier to work with for
-// the ui/surface code.
-
-#ifndef UI_SURFACE_D3D9_UTILS_WIN_H_
-#define UI_SURFACE_D3D9_UTILS_WIN_H_
-
-#include <d3d9.h>
-
-#include "base/basictypes.h"
-#include "ui/surface/surface_export.h"
-
-namespace base {
-class ScopedNativeLibrary;
-}
-
-namespace gfx {
-class Size;
-}
-
-namespace ui_surface_d3d9_utils {
-
-// Visible for testing. Loads the Direct3D9 library. Returns true on success.
-SURFACE_EXPORT
-bool LoadD3D9(base::ScopedNativeLibrary* storage);
-
-// Visible for testing. Creates a Direct3D9 device suitable for use with the
-// accelerated surface code. Returns true on success.
-SURFACE_EXPORT
-bool CreateDevice(const base::ScopedNativeLibrary& d3d_module,
- D3DDEVTYPE device_type,
- uint32 presentation_interval,
- IDirect3DDevice9Ex** device);
-
-// Calls the Vista+ (WDDM1.0) variant of CreateTexture that semantically
-// opens a texture allocated (possibly in another process) as shared. The
-// shared texture is identified by its surface handle. The resulting texture
-// is written into |opened_texture|.
-//
-// Returns true on success.
-SURFACE_EXPORT
-bool OpenSharedTexture(IDirect3DDevice9* device,
- int64 surface_handle,
- const gfx::Size& size,
- IDirect3DTexture9** opened_texture);
-
-// Create a one-off lockable surface of a specified size.
-//
-// Returns true on success.
-SURFACE_EXPORT
-bool CreateTemporaryLockableSurface(IDirect3DDevice9* device,
- const gfx::Size& size,
- IDirect3DSurface9** surface);
-
-// Create a one-off renderable texture of a specified size. The texture object
-// as well as the surface object for the texture's level 0 is returned (callers
-// almost always need to use both).
-//
-// Returns true on success.
-SURFACE_EXPORT
-bool CreateTemporaryRenderTargetTexture(IDirect3DDevice9* device,
- const gfx::Size& size,
- IDirect3DTexture9** texture,
- IDirect3DSurface9** render_target);
-
-} // namespace ui_surface_d3d9_utils
-
-#endif // UI_SURFACE_D3D9_UTILS_WIN_H_
\ No newline at end of file diff --git a/ui/surface/surface.gyp b/ui/surface/surface.gyp index fa08607..d0ef432 100644 --- a/ui/surface/surface.gyp +++ b/ui/surface/surface.gyp @@ -66,13 +66,9 @@ 'sources': [ 'accelerated_surface_mac.cc', 'accelerated_surface_mac.h', - 'accelerated_surface_transformer_win.cc', - 'accelerated_surface_transformer_win.h', - 'accelerated_surface_transformer_win.hlsl', 'accelerated_surface_win.cc', 'accelerated_surface_win.h', - 'd3d9_utils_win.cc', - 'd3d9_utils_win.h', + 'accelerated_surface_win.hlsl', 'io_surface_support_mac.cc', 'io_surface_support_mac.h', 'surface_export.h', |