Browse Source

Reduced maximum texture resolution and added method for mip-map removal.

David Piuva 5 years ago
parent
commit
1f7cf85051

+ 5 - 0
Source/DFPSR/api/imageAPI.cpp

@@ -108,6 +108,11 @@ void dsr::image_generatePyramid(ImageRgbaU8& image) {
 		image->generatePyramid();
 		image->generatePyramid();
 	}
 	}
 }
 }
+void dsr::image_removePyramid(ImageRgbaU8& image) {
+	if (image) {
+		image->removePyramid();
+	}
+}
 bool dsr::image_hasPyramid(const ImageRgbaU8& image) {
 bool dsr::image_hasPyramid(const ImageRgbaU8& image) {
 	GET_OPTIONAL(image->texture.hasMipBuffer(), false);
 	GET_OPTIONAL(image->texture.hasMipBuffer(), false);
 }
 }

+ 22 - 1
Source/DFPSR/api/imageAPI.h

@@ -80,9 +80,30 @@ namespace dsr {
 	PackOrderIndex image_getPackOrderIndex(const ImageRgbaU8& image);
 	PackOrderIndex image_getPackOrderIndex(const ImageRgbaU8& image);
 
 
 // Texture
 // Texture
-	// TODO: A method for removing the pyramid
+	// Pre-condition: image must exist and qualify as a texture according to image_isTexture
+	// Side-effect: Creates a mip-map pyramid of lower resolution images from the current content
+	// If successful, image_hasPyramid should return true from the image
 	void image_generatePyramid(ImageRgbaU8& image);
 	void image_generatePyramid(ImageRgbaU8& image);
+	// Pre-condition: image must exist
+	// Side-effect: Removes image's mip-map pyramid, including its buffer to save memory
+	// If successful, image_hasPyramid should return false from the image
+	void image_removePyramid(ImageRgbaU8& image);
+	// Post-condition: Returns true iff image contains a mip-map pyramid generated by image_generatePyramid
+	// Returns false without a warning if the image handle is empty
 	bool image_hasPyramid(const ImageRgbaU8& image);
 	bool image_hasPyramid(const ImageRgbaU8& image);
+	// Post-condition: Returns true iff image fulfills the criterias for being a texture
+	// Texture criterias:
+	//  * Each dimension of width and height should be a power-of-two
+	//    width = 2 ^ N
+	//    height = 2 ^ N
+	//  * Width and height should also be from 4 to 16384 pixels
+	//    Large enough to allow padding-free SIMD vectorization of 128-bit vectors (4 x 32 = 128)
+	//    Small enough to allow expressing the total size in bytes using a signed 32-bit integer
+	//    4 <= width <= 16384
+	//    4 <= height <= 16384
+	//  * Each row must consume the whole stride
+	//    Textures may not contain padding in the rows, but it's okay to use sub-images from a vertical atlas where the whole width is consumed
+	// Returns false without a warning if the image handle is empty
 	bool image_isTexture(const ImageRgbaU8& image);
 	bool image_isTexture(const ImageRgbaU8& image);
 
 
 // Pixel access
 // Pixel access

+ 17 - 5
Source/DFPSR/image/ImageRgbaU8.cpp

@@ -110,7 +110,7 @@ static int32_t getSizeGroup(int32_t size) {
 	} else if (size == 2) {
 	} else if (size == 2) {
 		group = 1; // Too small for 16-byte alignment!
 		group = 1; // Too small for 16-byte alignment!
 	} else if (size == 4) {
 	} else if (size == 4) {
-		group = 2;
+		group = 2; // Smallest allowed texture dimension
 	} else if (size == 8) {
 	} else if (size == 8) {
 		group = 3;
 		group = 3;
 	} else if (size == 16) {
 	} else if (size == 16) {
@@ -134,9 +134,9 @@ static int32_t getSizeGroup(int32_t size) {
 	} else if (size == 8192) {
 	} else if (size == 8192) {
 		group = 13;
 		group = 13;
 	} else if (size == 16384) {
 	} else if (size == 16384) {
-		group = 14; // Not recommended to use!
+		group = 14; // Largest allowed texture dimension
 	} else if (size == 32768) {
 	} else if (size == 32768) {
-		group = 15; // Exceeding the address space of 32-bit pointers!
+		group = 15; // May exceed the the address space of 32-bit pointers! Not allowed for textures.
 	}
 	}
 	return group;
 	return group;
 }
 }
@@ -196,8 +196,8 @@ void ImageRgbaU8Impl::generatePyramid() {
 	if (!this->isTexture()) {
 	if (!this->isTexture()) {
 		if (this->width < 4 || this->height < 4) {
 		if (this->width < 4 || this->height < 4) {
 			printText("Cannot generate a pyramid from an image smaller than 4x4 pixels.\n");
 			printText("Cannot generate a pyramid from an image smaller than 4x4 pixels.\n");
-		} else if (this->width > 32768 || this->height > 32768) {
-			printText("Cannot generate a pyramid from an image larger than 32768x32768 pixels.\n");
+		} else if (this->width > 16384 || this->height > 16384) {
+			printText("Cannot generate a pyramid from an image larger than 16384x16384 pixels.\n");
 		} else if (getSizeGroup(this->width) == -1 || getSizeGroup(this->height) == -1) {
 		} else if (getSizeGroup(this->width) == -1 || getSizeGroup(this->height) == -1) {
 			printText("Cannot generate a pyramid from image dimensions that are not powers of two.\n");
 			printText("Cannot generate a pyramid from image dimensions that are not powers of two.\n");
 		} else if (this->stride > this->width * pixelSize) {
 		} else if (this->stride > this->width * pixelSize) {
@@ -238,6 +238,18 @@ void ImageRgbaU8Impl::generatePyramid() {
 	}
 	}
 }
 }
 
 
+void ImageRgbaU8Impl::removePyramid() {
+	// Only try to remove if it has a pyramid
+	if (this->texture.pyramidBuffer.get() != nullptr) {
+		// Remove the pyramid's buffer
+		this->texture.pyramidBuffer = std::shared_ptr<Buffer>();
+		// Re-initialize
+		for (int32_t m = 0; m < MIP_BIN_COUNT; m++) {
+			this->texture.mips[m] = TextureRgbaLayer(imageInternal::getSafeData<uint8_t>(*this).getUnsafe(), this->width, this->height);
+		}
+	}
+}
+
 void ImageRgbaU8Impl::initializeRgbaImage() {
 void ImageRgbaU8Impl::initializeRgbaImage() {
 	// If the image fills the criterias of a texture
 	// If the image fills the criterias of a texture
 	if (getSizeGroup(this->width) >= 2
 	if (getSizeGroup(this->width) >= 2

+ 3 - 2
Source/DFPSR/image/ImageRgbaU8.h

@@ -43,8 +43,8 @@ struct TextureRgbaLayer {
 	// Can it be sampled as a texture
 	// Can it be sampled as a texture
 	bool exists() const { return this->data != nullptr; }
 	bool exists() const { return this->data != nullptr; }
 };
 };
-
-#define MIP_BIN_COUNT 5
+
+#define MIP_BIN_COUNT 5
 
 
 // Pointing to the parent image using raw pointers for fast rendering. Not not separate from the image!
 // Pointing to the parent image using raw pointers for fast rendering. Not not separate from the image!
 struct TextureRgba {
 struct TextureRgba {
@@ -72,6 +72,7 @@ public:
 	TextureRgba texture; // The texture view
 	TextureRgba texture; // The texture view
 	void initializeRgbaImage(); // Points to level 0 from all bins to allow rendering
 	void initializeRgbaImage(); // Points to level 0 from all bins to allow rendering
 	void generatePyramid(); // Fills the following bins with smaller images
 	void generatePyramid(); // Fills the following bins with smaller images
+	void removePyramid();
 	bool isTexture() const;
 	bool isTexture() const;
 	static bool isTexture(const ImageRgbaU8Impl* image); // Null cannot be sampled as a texture
 	static bool isTexture(const ImageRgbaU8Impl* image); // Null cannot be sampled as a texture
 public:
 public:

+ 4 - 0
Source/test/tests/ImageTest.cpp

@@ -38,6 +38,10 @@ START_TEST(Image)
 		ASSERT_EQUAL(image_hasPyramid(image), false);
 		ASSERT_EQUAL(image_hasPyramid(image), false);
 		image_generatePyramid(image);
 		image_generatePyramid(image);
 		ASSERT_EQUAL(image_hasPyramid(image), true);
 		ASSERT_EQUAL(image_hasPyramid(image), true);
+		image_removePyramid(image);
+		ASSERT_EQUAL(image_hasPyramid(image), false);
+		image_generatePyramid(image);
+		ASSERT_EQUAL(image_hasPyramid(image), true);
 	}
 	}
 END_TEST
 END_TEST