Chế độ đồ hoạ toàn màn hình cho phép chương trình 3D khai thác tối đa sức mạnh đồ hoạ của máy tính. Hầu hết các chương trình game 3D hiện nay chỉ hỗ trợ chế độ toàn màn hình.
Khi chương trình khởi động chế độ toàn màn hình, màn hình sẽ tự động chuyển sang độ phân giải được chọn. Ở chế độ này, chương trình sẽ sử dụng toàn bộ không gian màn hình để hiển thị hình ảnh, tất cả các chương trình khác sẽ không hiển thị trên màn hình kể cả các chương trình đặt always on top.
Trong bài này, tôi giới thiệu một chương trình cho phép chạy ở chế độ toàn màn hình với độ phân giải 800×600. Chương trình này cải tiến từ chương trình D3DTexture giới thiệu trong bài trước.
Khởi động chế độ toàn màn hình
Để khởi động chế đồ hoạ toàn màn hình, cần phải đặt những thông số sau:
- Đặt thuộc tính FormBorderStyle của cửa sổ chính là None
- Đặt thuộc tính Windowed của đối tượng PresentParameters khi tạo Device là false.
- Đặt BackBufferWidth và BackBufferHeight bằng kích cỡ cửa sổ. Độ rông và độ cao của cửa sổ phải tương ứng với một chế độ đồ hoạ cần khởi động, ví dụ 800×600.
PresentParameters presentParameters = new PresentParameters(); presentParameters.Windowed = false; presentParameters.BackBufferWidth = ClientSize.Width; presentParameters.BackBufferHeight = ClientSize.Height;
Với những thông số như vậy, chương trình sẽ chạy ở chế độ toàn màn hình với độ phân giải tương ứng.
Vấn đề Device Lost và kỹ thuật xử lý
Khi chương trình chạy ở chế độ toàn màn hình, nếu nhấn Alt-Tab để chuyển về màn hình desktop của Windows hoặc chuyển sang chương trình khác, chương trình sẽ lỗi và thoát.
Nguyên nhân ở đây là do chương trình không có quyền vẽ lên màn hình khi chuyển sang chương trình khác. Hiện tượng này gọi là Device Lost.
Device Lost sẽ xảy ra khi chương trình 3D đang chạy ở chế độ toàn màn hình và bị mất focus, khi lock máy hoặc khi Windows chuyển sang chế độ Screen Saver. Khi xảy ra Device Lost, chương trình không thể vẽ được nữa, các thông tin RenderState của Device bị phá huỷ, các dữ liệu đã được nạp như VertexBuffer, Texture không sử dụng được nữa. Trong trường hợp này, nếu chương trình cứ tiếp tục vẽ và gọi phương thức Present của Device thì sẽ bị lỗi.
Khi người dùng nhấn Alt-Tab hoặc nhấn vào nút dưới thanh Taskbar để chuyển trở lại chương trình, khi đó Device ở trạng thái sẵn sàng reset, và có thể tiếp tục vẽ sau khi reset.
Để xử lý được vấn đề Device Lost, theo các bước sau:
- Kiểm tra trạng thái Device, nếu bình thường thì tiến hành vẽ, nếu không tức là đã xảy ra Device Lost, chuyển sang bước 2.
- Khi xảy ra Device Lost, dừng việc vẽ, giải phóng toàn bộ tài nguyên gắn với Device như Texture, VertexBuffer, Surface… bằng cách gọi phương thức OnDeviceLost trên các đối tượng này (nếu có), hoặc Dispose để huỷ hoàn toàn.
- Kiểm tra định kỳ trạng thái Device, nếu trạng thái Device vẫn là Lost thì chờ và tiếp tục kiểm tra sau một khoảng thời gian. Nếu trạng thái Device là sẵn sàng reset, chuyển sang bước 4.
- Tiến hành Reset Device và tạo lại toàn bộ dữ liệu đã giải phóng trước đó bằng cách gọi phương thức OnDeviceReset (nếu trước đó gọi OnDeviceLost) hoặc tạo lại bằng new (nếu trước đó giải phóng bằng Dispose), sau đó có thể tiến hành vẽ bình thường.
Để kiểm tra trạng thái Device xem có bình thường hay không, dùng phương thức Device.CheckCooperativeLevel(). Nếu phương thức này trả về true thì có nghĩa là bình thường, nếu trả về false là Device Lost.
Trong khi Device Lost, để kiểm tra xem Device có ở trạng thái sẵn sàng cho việc reset hay chưa, dùng phương thức Device.TestCooperativeLevel(). Nếu phương thức trả về bình thường, hoặc quăng ra ngoại lệ DeviceNotResetException có nghĩa là đã sẵn sàng cho việc reset, nếu không phương thức sẽ quăng ra ngoại lệ DeviceLostException.
Để reset Device, gọi phương thức Device.Reset().
Chi tiết về các lệnh này có thể tham khảo trong chương trình minh hoạ.
Managed Pool và Default Pool
Nếu sử dụng chương trình D3DFrame được giới thiệu trong bài trước và bổ sung các phần hỗ trợ Fullscreen và xử lý Device Lost như trên, khi chạy nếu nhấn Alt-Tab để chuyển thì khi chuyển về chương trình chạy tiếp bình thường. Tuy nhiên nếu lock máy thì chỉ lần đầu quay trở lại là thành công, từ lần thứ 2 trở đi sẽ bị lỗi.
Một số ý kiến cho rằng hiện tượng này là lỗi của bộ DirectX SDK, tuy nhiên không thấy Microsoft đề cập trong MSDN.
Khi tạo các đối tượng như VertextBuffer, Texture, Surface… có một tham số phải chỉ ra đó là Pool. Thông thường, các lệnh tạo chỉ hợp lệ khi dùng Pool.Managed hoặc Pool.Default, các Pool khác có thể đọc thêm trong MSDN.
Default Pool là vùng nhớ ngầm định được sử dụng khi tạo các đối tượng. Các đối tượng này sẽ KHÔNG thể sử dụng lại nếu Device Lost.
Managed Pool là vùng nhớ được quản lý, các đối tượng tạo trong Managed Pool sẽ CÓ thể sử dụng lại khi Device Lost.
Chưa thấy tài liệu nào đề cập đến vấn đề hiệu năng khi chọn lựa giữa hai vùng này, tuy nhiên qua thực nghiệm cho thấy tốc độ là như nhau. Do đó chúng ta nên sử dụng vùng nhớ Managed Pool trong mọi trường hợp nếu có thể.
Đối với VertexBuffer, tạo với Pool.Managed và Usage.WriteOnly. Nếu tạo với Pool.Default, chương trình sẽ bị lỗi sau 2 lần lock máy.
Đối với Texture, tạo với Pool.Managed và Usage.None.
Chi tiết về cách tạo các đối tượng này có thể xem thêm trong chương trình minh hoạ.
Khi chạy, chương trình sẽ hiển thị toàn màn hình, người dùng có thể ấn Alt-Tab, hoặc lock máy nhiều lần, chương trình sẽ tiếp tục khi focus.
Tải về: chương trình minh hoạ
Ghi chú: Để dịch và chạy được chương trình này, máy tính cần cài đặt các công cụ cần thiết. Để biết thêm chi tiết, xem thêm các bài trước về Direct3D.



