2012-09-03 13 views
5

Tôi có kiến ​​thức cơ bản về việc sử dụng OpenGL, đặc biệt là trên Android. Tôi đang phát triển một ứng dụng sử dụng OpenGL để chuyển đổi giữa các hình ảnh toàn màn hình một cách nhanh chóng (vì nó quá chậm bằng cách sử dụng khung Android bình thường).Cách tải họa tiết trong OpenGL ES hiệu quả

Những gì tôi đã tìm thấy là để load texture, tôi cần phải làm một cái gì đó như:

ByteBuffer byteBuffer = ByteBuffer.allocateDirect(vertices.length * 4); 
byteBuffer.order(ByteOrder.nativeOrder()); 
vertexBuffer = byteBuffer.asFloatBuffer(); 
vertexBuffer.put(vertices); 
vertexBuffer.position(0); 
byteBuffer = ByteBuffer.allocateDirect(texture.length * 4); 
byteBuffer.order(ByteOrder.nativeOrder()); 
textureBuffer = byteBuffer.asFloatBuffer(); 
textureBuffer.put(texture); 
textureBuffer.position(0); 
_gl = gl; 
final Bitmap bitmap = BitmapFactory.decodeResource(context.getResources(), _imageResourceId); 
gl.glGenTextures(1, textures, 0); 
gl.glBindTexture(GL10.GL_TEXTURE_2D, textures[0]); 
gl.glTexParameterf(GL10.GL_TEXTURE_2D, GL10.GL_TEXTURE_MIN_FILTER, GL10.GL_NEAREST); 
gl.glTexParameterf(GL10.GL_TEXTURE_2D, GL10.GL_TEXTURE_MAG_FILTER, GL10.GL_LINEAR); 
GLUtils.texImage2D(GL10.GL_TEXTURE_2D, 0, bitmap, 0); 
bitmap.recycle(); 

Bây giờ, kể từ khi những hình ảnh có nghĩa là để được toàn màn hình (và họ là khá lớn - 1024x1024), điều này mất một thời gian, đặc biệt là kể từ khi tôi cần phải tải 5 trong số họ cùng một lúc.

Vì vậy, tôi cần phải hỏi một số câu hỏi liên quan đến lời khuyên của việc cải thiện mã, đặc biệt là về tải hiệu quả (nhưng cũng sử dụng ít bộ nhớ nếu có thể):

  1. nếu tôi giải mã bitmap không có pixel minh bạch, bằng cách sử dụng định dạng RGB_565, nó sẽ tăng tốc độ tải hình ảnh lên OpenGL (hay giai đoạn giải mã)?

  2. bitmap đầu vào phải có chiều rộng và chiều cao là 2 hoặc tôi có thể để OpenGL chỉ lấy phần mà nó muốn, có quy tắc này không? Ý tôi là, có lẽ tôi có thể thực hiện lệnh texImage2D để chỉ lấy một phần của bitmap?

  3. có lẽ tôi thậm chí chỉ có thể giải mã phần này ngay từ đầu (vì vậy nếu tôi có hình ảnh cực lớn 10000x10000, tôi chỉ có thể giải mã một phần 1024x1024 của nó và đưa nó cho OpenGL)?

  4. có thể tải và chỉ hiển thị hình ảnh đầu tiên và trong nền tải phần còn lại không? Tôi đã nghe nói rằng bạn không thể gửi bitmap cho OpenGL trong một chủ đề mà không phải là một trong đó xử lý nó. Liệu có ý nghĩa khi tải chúng theo phương pháp của số GlRenderer, nói lần thứ hai nó được gọi? Tôi nhớ tôi đã nghe nói về một mẹo về sáp nhập nhiều hình ảnh vào một hình ảnh duy nhất (cái khác, từ trái sang phải), để nó có thể có một số tăng tốc độ cho giai đoạn giải mã. Không chắc tên của kỹ thuật này là gì. Vẫn có thể sử dụng OpenGL ES trên Android?

  5. là có thể tránh tạo ra một thể hiện Bitmap và để giải mã được thực hiện theo cách bản địa hơn (NDK, có lẽ)? Theo các thử nghiệm của tôi, việc giải mã một tệp PNG có kích thước 1024x1024 trên trình mô phỏng mất khoảng 400ms-700ms, nhưng việc gửi nó tới OpenGL mất khoảng 50ms-70ms.

  6. sử dụng Procrank, tôi đã phát hiện ra rằng OpenGL có thể chiếm nhiều bộ nhớ. Có thể làm cho nó sử dụng ít bộ nhớ hơn? Có thể sử dụng các loại kết cấu tốt hơn?

  7. vì Android có thể hoạt động trên nhiều loại thiết bị, có thể đưa vào tệp kê khai yêu cầu cần bao nhiêu bộ nhớ để ứng dụng chạy, để những người có quá ít bộ nhớ sẽ không thể cài đặt nó?


@Majid Max:

  1. do đó, nó đủ để giải mã theo cách này và gửi nó đến OpenGL, hoặc nên tôi cũng đặt một cái gì đó đặc biệt khi gửi đến OpenGL?

  2. không có lệnh như vậy để tham gia một phần của bitmap?

  3. Ý tôi là, tôi có thể giải mã chỉ một phần của tệp được lưu trữ trong bitmap không, thay vì tất cả bitmap?

  4. vì vậy điều duy nhất tôi có thể làm để tải mọi thứ ngay từ đầu và sau đó sử dụng tất cả? Lam thê nao điêu đo co thể? Trò chơi xử lý nó như thế nào? Ý tôi là, họ thể hiện một giai đoạn khác, ngay cả với một cái gì đó trông giống như một thanh tiến trình OpenGL tạo ra. Điều này rất có vấn đề.

  5. nội dung tôi mô tả cũng khả dụng trên web. Ví dụ: thay vì tải nhiều hình ảnh nhỏ, trang web chứa một hình ảnh duy nhất và ánh xạ phần nào của nó sẽ được hiển thị ở đâu. Một tên khác cho nó là sprites. Ví dụ here.

  6. Tôi hiểu. Tôi đoán tôi cũng nên gọi glDeleteTextures khi tôi thấy không được sử dụng nữa, phải không?

  7. làm cách nào để làm điều đó? Tôi nên thay đổi gì trong mã?

  8. điều gì xảy ra khi tôi sử dụng nhiều bộ nhớ? Có một thứ như RAM ảo (sử dụng bộ nhớ trong có lẽ) khi không có RAM miễn phí? Tôi đã nghe về nó trên Google IO video, nhưng có vẻ như họ không chắc chắn về câu trả lời là tốt. Liên kết here. Họ chỉ nói để mong đợi nhiều sự cố hơn khi một điều như vậy xảy ra.


@Majid Max:

1 + 2 + 3. ?

  1. điều này có thể hiệu quả. Bạn có nghĩa là tôi thực hiện một chủ đề mới sẽ tải các bitmap, và sau đó gửi kết quả trở lại chủ đề OpenGL mà sẽ ràng buộc các kết cấu với bitmap? Có lẽ tôi có thể sử dụng cách tiếp cận tương tự như asyncTask và sử dụng publishprogress.

  2. đó cũng là một điều tốt. Bạn có bất kỳ liên kết tôi nên đọc về nó? Hoặc có thể một đoạn mã để thay đổi trong mã của tôi?

  3. cảm ơn.

  4. vì vậy tôi nghĩ đó là điều dễ nhất để sử dụng ETC1. Tuy nhiên nó không hỗ trợ minh bạch, vì vậy theo this link, tôi cần phải sử dụng một kết cấu khác chỉ cho điều đó, nhưng tôi không thể tìm thấy một mẫu cho việc này.

  5. Tôi có thể giả định gì về bộ nhớ khả dụng mà tôi có thể sử dụng? Ví dụ: tôi có thể giả định rằng tất cả các thiết bị Android có thể cung cấp cho tôi 200MB bộ nhớ video mà tôi có thể sử dụng cho OpenGL không?

Trả lời

-1

Tôi nghĩ bạn nên kiểm tra http://www.andengine.org/ Nó sẽ giúp bạn tiết kiệm rất nhiều thời gian và công việc ...

+0

thật đáng tiếc là tôi không thể sử dụng vì tôi cần làm việc với cả API Android và OpenGL. tôi biết về giải pháp này (và libGDX). Tôi chỉ không được phép sử dụng chúng, đặc biệt là kể từ khi tôi cần phải đặt các quan điểm trong một viewPager. –

5
  1. vâng, nếu bạn không cần tính minh bạch (alpha) sử dụng một định dạng không có alpha, và các định dạng nhỏ hơn như (RGB565) có nghĩa là kết cấu kích thước nhỏ hơn chắc chắn tăng tốc độ giải mã và tải lên opengl.

  2. Chắc chắn CÓ, nếu bạn tải kết cấu không có chiều rộng/chiều cao 2 chiều, opengl sẽ phân bổ họa tiết với sức mạnh tiếp theo là 2 (513/513 texture sẽ trở thành 1024/1024), và điều đó có nghĩa là bạn lãng phí bộ nhớ vram. và bạn không thể lệnh opengl để lấy một phần của hình ảnh bởi vì "teximage2d" mất chiều rộng/chiều cao của hình ảnh được tải và chỉ định bất kỳ giá trị nào khác sẽ cung cấp cho bạn hình ảnh bị hỏng (nếu không nghiền ứng dụng).

  3. không có nhận xét.

  4. Tôi không chắc chắn về điều đó, đã có công cụ hiển thị đa luồng dựa trên opengl. và bạn có thể tải một kết cấu (từ chủ đề khác) trong khi phát hành một lệnh kết xuất (ít nhất là trong C/C++ gốc, không chắc chắn về java). và NO, không bao giờ cố gắng tải một kết cấu trong vòng lặp dựng hình, đó là thực hành không tốt.

  5. không chắc chắn những gì bạn có nghĩa là ở đây

  6. đây là cách tốt nhất, các mã gốc (C/C++) luôn luôn tốt hơn

  7. (nếu bạn có ý nghĩa VRAM đây) vâng, sử dụng một kết cấu nén định dạng như ETC1, PVRTC, ATC luôn luôn là một ý tưởng tốt, nó mất ít bộ nhớ vram và mang lại hiệu suất tốt hơn.

  8. xem xét chuyển sang giải pháp dự phòng (thậm chí nhiều họa tiết nhỏ hơn) thay vì cắt các thiết bị cấp thấp hơn.

EDIT:

4 .. bạn bắt đầu tải nội dung (hình ảnh) trong một thread riêng biệt mà chỉ ra các rendering sợi tỷ lệ quá trình tải, điều này có thể được sử dụng để vẽ một thanh tiến trình cho quá trình tải.

5 .. mẹo này được gọi là "họa tiết kết cấu" và đó là để tăng tốc độ hiển thị không tải.

6 .. sau khi tải hình ảnh được giải mã thành kết cấu tròn, bạn có thể xóa hình ảnh đã giải mã (từ bộ nhớ hệ thống) so với tải hình tiếp theo. và sau khi bạn thực hiện bằng cách sử dụng kết cấu opengl bạn có thể xóa nó (từ bộ nhớ video).

7 .. kết cấu nén là phần mở rộng opengl phần cứng cụ thể, vì vậy bạn phải kiểm tra xem phần mở rộng nén kết cấu có hiện diện không và sau đó sử dụng nó với hàm "glCompressedTexImage2D" thay vì "texImage2D". PVRTC cho GPU PowerVR; ATC dành cho GPU AMD; ASTC dành cho GPU Mali; ETC1 định dạng họa tiết chuẩn (được hỗ trợ trong android 2.2+).

8 .. khi bạn tải xong hình ảnh lên kết cấu mờ, hình ảnh không còn cần thiết nữa. vì vậy bạn phải giải phóng ram từ nội dung không cần thiết (hình ảnh).

EDIT2:

5 .. http://http.download.nvidia.com/developer/NVTextureSuite/Atlas_Tools/Texture_Atlas_Whitepaper.pdf

7 ..sau khi bạn đã tải hai kết cấu ETC (ví dụ: texture đầu tiên giữ màu và alpha thứ hai trong kênh màu đỏ) bằng cách sử dụng "glCompressedTexImage2D" trong opengl (cho phép nói textureId1, textureId2), kết hợp hai họa tiết trong hai đơn vị kết cấu:

glActiveTexture(GL_TEXTURE0); 
glBindTexture(GL_TEXTURE_2D, textureId1); 

glActiveTexture(GL_TEXTURE1); 
glBindTexture(GL_TEXTURE_2D, textureId2); 

và sau đó tạo ra một chương trình đổ bóng với shader đoạn sau:

uniform sampler2D  sTexture1; 
uniform sampler2D  sTexture2; 
varying mediump vec2 vTexCoord; 

void main() 
{ 
    gl_FragColor.rgb = texture2D(sTexture1, vTexCoord).rgb; 
    gl_FragColor.a = texture2D(sTexture2, vTexCoord).r; 
} 

cuối cùng, ràng buộc hai lấy mẫu kết cấu đổ bóng để hai đơn vị kết cấu (mà điểm đến hai ETC textures):

GLint texture1Sampler = glGetUniformLocation(programObject, "sTexture1"); 
GLint texture2Sampler = glGetUniformLocation(programObject, "sTexture2"); 

glUniform1i(texture1Sampler, GL_TEXTURE0); 
glUniform1i(texture2Sampler, GL_TEXTURE1); 

8 .. bạn không thể giả định bất cứ điều gì, bạn tiếp tục phân bổ kết cấu và bộ đệm (khi cần) cho đến khi bạn nhận được GL_OUT_OF_MEMORY, hơn bạn phải giải phóng các tài nguyên không sử dụng khác (kết cấu, bộ đệm, ...).

+0

cảm ơn câu trả lời. xin vui lòng xem câu hỏi cập nhật của tôi cho ý kiến ​​về câu trả lời của bạn. –

+0

tôi đã cập nhật câu trả lời của tôi, tôi hy vọng điều này sẽ giúp. –

+0

@Majid: ASTC chưa có trên bất kỳ thứ gì. Đối với các hệ thống dựa trên Mali, tôi nghĩ bạn cần sử dụng ETC, cũng được * tiếp xúc * trên một số hệ thống khác (tùy thuộc vào nhà cung cấp) –