2015-10-15 25 views
5

Tôi đang viết một ứng dụng đọc sách điện tử cho Windows Store. Tôi đang sử dụng chuỗi trao đổi Direct2D + DXGI để hiển thị các trang sách trên màn hình.Đa luồng Direct2D hiệu quả

Nội dung sách của tôi đôi khi khá phức tạp (hình học, bitmap, mặt nạ, v.v.), vì vậy có thể mất đến 100 mili giây để hiển thị nội dung sách. Vì vậy, tôi đang cố gắng để làm một màn hình hiển thị off-bit cho một bitmap trong một chủ đề riêng biệt, và sau đó chỉ hiển thị bitmap này trong chủ đề chính.

Tuy nhiên, tôi không thể biết cách thực hiện điều đó một cách hiệu quả.

Cho đến nay tôi đã thử hai cách tiếp cận:

  1. Sử dụng một đơn ID2D1Factory với D2D1_FACTORY_TYPE_MULTI_THREADED cờ, tạo ID2D1BitmapRenderTarget và sử dụng nó trong chủ đề nền cho vẽ ra màn hình. (Điều này bổ sung yêu cầu ID2D1Multithread::Enter/Leave trên các hoạt động IDXGISwapChain::Present). Vấn đề là, hoạt động ID2D1RenderTarget::EndDraw trong chủ đề nền đôi khi mất đến 100ms và hiển thị chuỗi chính bị chặn trong khoảng thời gian này do khóa Direct2D bên trong.

  2. Sử dụng ID2D1Factory riêng biệt trong chuỗi nền (như được mô tả trong http://www.sdknews.com/ios/using-direct2d-for-server-side-rendering) và tắt đồng bộ hóa Direct2D bên trong. Không có cross-locking betwen hai chủ đề trong trường hợp này. Thật không may, trong trường hợp này tôi không thể sử dụng kết quả bitmap trong chính ID2D1Factory trực tiếp, bởi vì nó thuộc về một nhà máy khác nhau. Tôi phải di chuyển dữ liệu bitmap vào bộ nhớ CPU, sau đó sao chép nó vào bộ nhớ GPU của chính ID2D1Factory. Hoạt động này cũng giới thiệu các sự chậm trễ đáng kể (tôi tin rằng đó là do truy cập bộ nhớ lớn, nhưng tôi không chắc chắn).

Có cách nào để thực hiện điều này một cách hiệu quả không?

P.S. Tất cả thời gian ở đây được cung cấp cho Acer Switch 10 tablet. Trên PC Core i7 thông thường, cả hai cách tiếp cận hoạt động mà không có bất kỳ độ trễ hiển thị nào.

Trả lời

4

Ok, tôi đã tìm được giải pháp.

Về cơ bản, tất cả những gì tôi cần là sửa đổi cách tiếp cận 2 để sử dụng chia sẻ tài nguyên DXGI giữa hai bộ nhà máy DirectX. Tôi sẽ bỏ qua tất cả các chi tiết đẫm máu (chúng có thể được tìm thấy ở đây: http://xboxforums.create.msdn.com/forums/t/66208.aspx), nhưng bước cơ bản là:

  1. Tạo hai bộ nguồn DirectX: main (mà sẽ được sử dụng để vẽ trên màn hình), và trung học (để hiển thị offscreen).
  2. Sử dụng ID3D11Device2 từ bộ tài nguyên chính, tạo kết cấu D3D 2D theo CreateTexture2DD3D11_BIND_RENDER_TARGET, D3D11_BIND_SHADER_RESOURCE, D3D11_RESOURCE_MISC_SHARED_NTHANDLED3D11_RESOURCE_MISC_SHARED_KEYEDMUTEX cờ.
  3. Nhận xử lý được chia sẻ từ nó bằng cách truyền nó đến IDXGIResource1 và gọi CreateSharedHandle từ số này với XGI_SHARED_RESOURCE_READDXGI_SHARED_RESOURCE_WRITE.
  4. Mở kết cấu được chia sẻ này trong bộ tài nguyên phụ trong chuỗi nền bằng cách gọi ID3D11Device2::OpenSharedResource1.
  5. Lấy đột biến có khóa của kết cấu này (IDXGIKeyedMutex::AcquireSync), tạo mục tiêu hiển thị từ nó (ID2D1Factory2::CreateDxgiSurfaceRenderTarget), vẽ trên đó và nhả mutex (IDXGIKeyedMutex::ReleaseSync).
  6. Trên chủ đề chính, trong tập tài nguyên chính, có được mutex và tạo bitmap chia sẻ từ kết cấu được tạo ở bước 2, vẽ bitmap này, sau đó nhả mutex.

Lưu ý rằng công cụ khóa mutex là cần thiết. Không làm điều đó dẫn đến một số thông báo lỗi gỡ lỗi DirectX khó hiểu và hoạt động sai hoặc thậm chí bị lỗi.

0

tl; dr: Hiển thị bitmap trên chuỗi nền trong chế độ phần mềm. Vẽ từ bitmap để hiển thị mục tiêu trên chuỗi giao diện người dùng trong chế độ phần cứng.

Cách tiếp cận tốt nhất mà tôi đã có thể tìm thấy cho đến nay là sử dụng đề nền với phần mềm vẽ (IWICImagingFactory::CreateBitmapID2D1Factory::CreateWicBitmapRenderTarget) và sau đó sao chép nó vào một bitmap phần cứng trở lại trên các chủ đề với phần cứng Đích kết xuất qua ID2D1RenderTarget::CreateBitmapFromWicBitmap . Và sau đó blit rằng sử dụng ID2D1RenderTarget::DrawBitmap.

Đây là cách paint.net 4.0 hiển thị lựa chọn. Khi bạn vẽ một vùng chọn bằng công cụ Lasso, nó sẽ sử dụng một chuỗi nền để vẽ đường viền chọn không đồng bộ (chuỗi giao diện người dùng không chờ cho việc này hoàn thành). Bạn có thể kết thúc với một đa giác rất phức tạp do phong cách đột quỵ và hình động. Tôi render nó 4 lần, trong đó mỗi khung hình động có độ lệch hơi khác nhau đối với kiểu nét đứt nét.

Rõ ràng việc hiển thị này có thể mất một thời gian vì đa giác trở nên phức tạp hơn (tức là, nếu bạn tiếp tục viết nguệch ngoạc một lúc). Tôi có một vài tối ưu hóa đặc biệt khác khi bạn sử dụng công cụ Move Selection cho phép bạn thực hiện các phép biến đổi (xoay, dịch, tỉ lệ): nếu chủ đề nền chưa tái hiện đa giác hiện tại với biến đổi mới, thì tôi sẽ hiển thị bitmap cũ (với đa giác hiện tại và biến đổi cũ) với biến đổi mới được áp dụng. Đường viền lựa chọn có thể bị bóp méo (mở rộng) hoặc cắt bớt (được dịch bên ngoài khu vực có thể xem được) trong khi luồng nền bắt kịp, nhưng đó là một mức giá nhỏ để trả cho phản hồi 60fps.Tối ưu hóa này hoạt động rất tốt vì bạn không thể sửa đổi đa giác biến đổi của một lựa chọn cùng một lúc.