Browse Source

Error if a non-2D/affine matrix is used with auto-batched draws, since they perform CPU-side matrix transforms on 2-component vectors.

--HG--
branch : minor
Alex Szpakowski 8 years ago
parent
commit
70b32c47ce

+ 4 - 4
platform/xcode/liblove.xcodeproj/project.pbxproj

@@ -1453,7 +1453,7 @@
 		FA0B7B891A95902C000E1D17 /* Drawable.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = Drawable.h; sourceTree = "<group>"; };
 		FA0B7B8A1A95902C000E1D17 /* Graphics.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; lineEnding = 0; path = Graphics.cpp; sourceTree = "<group>"; xcLanguageSpecificationIdentifier = xcode.lang.cpp; };
 		FA0B7B8B1A95902C000E1D17 /* Graphics.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = Graphics.h; sourceTree = "<group>"; };
-		FA0B7B8D1A95902C000E1D17 /* Canvas.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = Canvas.cpp; sourceTree = "<group>"; };
+		FA0B7B8D1A95902C000E1D17 /* Canvas.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; lineEnding = 0; path = Canvas.cpp; sourceTree = "<group>"; xcLanguageSpecificationIdentifier = xcode.lang.cpp; };
 		FA0B7B8E1A95902C000E1D17 /* Canvas.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = Canvas.h; sourceTree = "<group>"; };
 		FA0B7B911A95902C000E1D17 /* Graphics.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; lineEnding = 0; path = Graphics.cpp; sourceTree = "<group>"; xcLanguageSpecificationIdentifier = xcode.lang.cpp; };
 		FA0B7B921A95902C000E1D17 /* Graphics.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = Graphics.h; sourceTree = "<group>"; };
@@ -1725,9 +1725,9 @@
 		FA1BA09C1E16CFCE00AA2803 /* Font.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = Font.h; sourceTree = "<group>"; };
 		FA1BA0A01E16D97500AA2803 /* wrap_Font.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = wrap_Font.cpp; sourceTree = "<group>"; };
 		FA1BA0A11E16D97500AA2803 /* wrap_Font.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = wrap_Font.h; sourceTree = "<group>"; };
-		FA1BA0A51E16F20600AA2803 /* Canvas.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = Canvas.cpp; sourceTree = "<group>"; };
-		FA1BA0A61E16F20600AA2803 /* Canvas.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = Canvas.h; sourceTree = "<group>"; };
-		FA1BA0AA1E16F9EE00AA2803 /* wrap_Canvas.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = wrap_Canvas.cpp; sourceTree = "<group>"; };
+		FA1BA0A51E16F20600AA2803 /* Canvas.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; lineEnding = 0; path = Canvas.cpp; sourceTree = "<group>"; xcLanguageSpecificationIdentifier = xcode.lang.cpp; };
+		FA1BA0A61E16F20600AA2803 /* Canvas.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; lineEnding = 0; path = Canvas.h; sourceTree = "<group>"; xcLanguageSpecificationIdentifier = xcode.lang.objcpp; };
+		FA1BA0AA1E16F9EE00AA2803 /* wrap_Canvas.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; lineEnding = 0; path = wrap_Canvas.cpp; sourceTree = "<group>"; xcLanguageSpecificationIdentifier = xcode.lang.cpp; };
 		FA1BA0AB1E16F9EE00AA2803 /* wrap_Canvas.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = wrap_Canvas.h; sourceTree = "<group>"; };
 		FA1BA0AF1E16FD0800AA2803 /* Shader.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = Shader.cpp; sourceTree = "<group>"; };
 		FA1BA0B01E16FD0800AA2803 /* Shader.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = Shader.h; sourceTree = "<group>"; };

+ 6 - 0
src/common/Matrix.cpp

@@ -250,6 +250,12 @@ void Matrix4::shear(float kx, float ky)
 	this->operator *=(t);
 }
 
+bool Matrix4::isAffine2DTransform() const
+{
+	return fabsf(e[2] + e[3] + e[6] + e[7] + e[8] + e[9] + e[11] + e[14]) < 0.00001f
+		&& fabsf(e[10] + e[15] - 2.0f) < 0.00001f;
+}
+
 Matrix4 Matrix4::inverse() const
 {
 	Matrix4 inv;

+ 7 - 0
src/common/Matrix.h

@@ -195,6 +195,13 @@ public:
 	template <typename Vdst, typename Vsrc>
 	void transform(Vdst *dst, const Vsrc *src, int size) const;
 
+	/**
+	 * Gets whether this matrix is an affine 2D transform (if the only non-
+	 * identity elements are the upper-left 4x4 and 2 translation values in the
+	 * 4th column).
+	 **/
+	bool isAffine2DTransform() const;
+
 	/**
 	 * Computes and returns the inverse of the matrix.
 	 **/

+ 7 - 7
src/modules/graphics/Canvas.cpp

@@ -62,10 +62,10 @@ Canvas::Canvas(const Settings &settings)
 	if (readable && isPixelFormatDepthStencil(format) && settings.msaa > 1)
 		throw love::Exception("Readable depth/stencil Canvases with MSAA are not currently supported.");
 
-	if ((!readable || settings.msaa > 1) && settings.mipmaps != MIPMAP_NONE)
+	if ((!readable || settings.msaa > 1) && settings.mipmaps != MIPMAPS_NONE)
 		throw love::Exception("Non-readable and MSAA textures cannot have mipmaps.");
 
-	mipmapCount = settings.mipmaps == MIPMAP_NONE ? 1 : getMipmapCount(pixelWidth, pixelHeight);
+	mipmapCount = settings.mipmaps == MIPMAPS_NONE ? 1 : getMipmapCount(pixelWidth, pixelHeight);
 
 	canvasCount++;
 }
@@ -111,14 +111,14 @@ bool Canvas::getConstant(MipmapMode in, const char *&out)
 	return mipmapModes.find(in, out);
 }
 
-StringMap<Canvas::MipmapMode, Canvas::MIPMAP_MAX_ENUM>::Entry Canvas::mipmapEntries[] =
+StringMap<Canvas::MipmapMode, Canvas::MIPMAPS_MAX_ENUM>::Entry Canvas::mipmapEntries[] =
 {
-	{ "none",   MIPMAP_NONE   },
-	{ "manual", MIPMAP_MANUAL },
-	{ "auto",   MIPMAP_AUTO   },
+	{ "none",   MIPMAPS_NONE   },
+	{ "manual", MIPMAPS_MANUAL },
+	{ "auto",   MIPMAPS_AUTO   },
 };
 
-StringMap<Canvas::MipmapMode, Canvas::MIPMAP_MAX_ENUM> Canvas::mipmapModes(Canvas::mipmapEntries, sizeof(Canvas::mipmapEntries));
+StringMap<Canvas::MipmapMode, Canvas::MIPMAPS_MAX_ENUM> Canvas::mipmapModes(Canvas::mipmapEntries, sizeof(Canvas::mipmapEntries));
 
 } // graphics
 } // love

+ 7 - 7
src/modules/graphics/Canvas.h

@@ -41,10 +41,10 @@ public:
 
 	enum MipmapMode
 	{
-		MIPMAP_NONE,
-		MIPMAP_MANUAL,
-		MIPMAP_AUTO,
-		MIPMAP_MAX_ENUM
+		MIPMAPS_NONE,
+		MIPMAPS_MANUAL,
+		MIPMAPS_AUTO,
+		MIPMAPS_MAX_ENUM
 	};
 
 	struct Settings
@@ -52,7 +52,7 @@ public:
 		int width  = 1;
 		int height = 1;
 		int layers = 1; // depth for 3D textures
-		MipmapMode mipmaps = MIPMAP_NONE;
+		MipmapMode mipmaps = MIPMAPS_NONE;
 		PixelFormat format = PIXELFORMAT_NORMAL;
 		TextureType type = TEXTURE_2D;
 		float pixeldensity = 1.0f;
@@ -86,8 +86,8 @@ protected:
 
 private:
 
-	static StringMap<MipmapMode, MIPMAP_MAX_ENUM>::Entry mipmapEntries[];
-	static StringMap<MipmapMode, MIPMAP_MAX_ENUM> mipmapModes;
+	static StringMap<MipmapMode, MIPMAPS_MAX_ENUM>::Entry mipmapEntries[];
+	static StringMap<MipmapMode, MIPMAPS_MAX_ENUM> mipmapModes;
 	
 }; // Canvas
 

+ 10 - 0
src/modules/graphics/Graphics.cpp

@@ -593,6 +593,16 @@ Graphics::StreamVertexData Graphics::requestStreamDraw(const StreamDrawRequest &
 	if (state.vertexCount == 0 && Shader::current != nullptr && req.texture != nullptr)
 		Shader::current->checkMainTexture(req.texture);
 
+	if (!getTransform().isAffine2DTransform())
+	{
+		for (CommonFormat fmt : req.formats)
+		{
+			int components = getFormatPositionComponents(fmt);
+			if (components > 0 && components < 3)
+				throw love::Exception("Obly affine 2D transforms are supported with auto-batched draws.");
+		}
+	}
+
 	bool shouldflush = false;
 	bool shouldresize = false;
 

+ 1 - 1
src/modules/graphics/opengl/Canvas.cpp

@@ -523,7 +523,7 @@ love::image::ImageData *Canvas::newImageData(love::image::Image *module, int sli
 
 void Canvas::generateMipmaps()
 {
-	if (getMipmapCount() == 1 || getMipmapMode() == MIPMAP_NONE)
+	if (getMipmapCount() == 1 || getMipmapMode() == MIPMAPS_NONE)
 		throw love::Exception("generateMipmaps can only be called on a Canvas which was created with mipmaps enabled.");
 
 	gl.bindTextureToUnit(this, 0, false);

+ 2 - 2
src/modules/graphics/opengl/Graphics.cpp

@@ -713,12 +713,12 @@ void Graphics::endPass()
 
 	for (const auto &rt : rts.colors)
 	{
-		if (rt.canvas->getMipmapMode() == Canvas::MIPMAP_AUTO && rt.mipmap == 0)
+		if (rt.canvas->getMipmapMode() == Canvas::MIPMAPS_AUTO && rt.mipmap == 0)
 			rt.canvas->generateMipmaps();
 	}
 
 	int dsmipmap = rts.depthStencil.mipmap;
-	if (depthstencil != nullptr && depthstencil->getMipmapMode() == Canvas::MIPMAP_AUTO && dsmipmap == 0)
+	if (depthstencil != nullptr && depthstencil->getMipmapMode() == Canvas::MIPMAPS_AUTO && dsmipmap == 0)
 		depthstencil->generateMipmaps();
 }
 

+ 17 - 0
src/modules/graphics/vertex.cpp

@@ -79,6 +79,23 @@ uint32 getFormatFlags(CommonFormat format)
 	}
 }
 
+int getFormatPositionComponents(CommonFormat format)
+{
+	switch (format)
+	{
+	case CommonFormat::NONE:
+	case CommonFormat::RGBAub:
+		return 0;
+	case CommonFormat::XYf:
+	case CommonFormat::XYf_STf:
+	case CommonFormat::XYf_STPf:
+	case CommonFormat::XYf_STf_RGBAub:
+	case CommonFormat::XYf_STus_RGBAub:
+	case CommonFormat::XYf_STPf_RGBAub:
+		return 2;
+	}
+}
+
 size_t getIndexDataSize(IndexDataType type)
 {
 	switch (type)

+ 5 - 0
src/modules/graphics/vertex.h

@@ -137,8 +137,13 @@ struct XYf_STPf_RGBAub
 };
 
 size_t getFormatStride(CommonFormat format);
+
 uint32 getFormatFlags(CommonFormat format);
+
+int getFormatPositionComponents(CommonFormat format);
+
 size_t getIndexDataSize(IndexDataType type);
+
 IndexDataType getIndexDataTypeFromMax(size_t maxvalue);
 
 int getIndexCount(TriangleIndexMode mode, int vertexCount);

+ 3 - 3
src/modules/graphics/wrap_Graphics.cpp

@@ -2519,7 +2519,7 @@ int w_push(lua_State *L)
 	if (luax_istype(L, 2, math::Transform::type))
 	{
 		math::Transform *t = luax_totype<math::Transform>(L, 2);
-		instance()->applyTransform(t);
+		luax_catchexcept(L, [&]() { instance()->applyTransform(t); });
 	}
 
 	return 0;
@@ -2571,14 +2571,14 @@ int w_origin(lua_State * /*L*/)
 int w_applyTransform(lua_State *L)
 {
 	math::Transform *t = math::luax_checktransform(L, 1);
-	instance()->applyTransform(t);
+	luax_catchexcept(L, [&]() { instance()->applyTransform(t); });
 	return 0;
 }
 
 int w_replaceTransform(lua_State *L)
 {
 	math::Transform *t = math::luax_checktransform(L, 1);
-	instance()->replaceTransform(t);
+	luax_catchexcept(L, [&]() { instance()->replaceTransform(t); });
 	return 0;
 }
 

+ 2 - 2
src/modules/graphics/wrap_Graphics.lua

@@ -204,7 +204,7 @@ GLSL.VERTEX = {
 #endif]],
 
 	FUNCTIONS = [[
-void updatePointSize() {
+void setPointSize() {
 #ifdef GL_ES
 	gl_PointSize = love_PointSize;
 #endif
@@ -224,7 +224,7 @@ vec4 position(mat4 transform_proj, vec4 vertpos);
 void main() {
 	VaryingTexCoord = VertexTexCoord;
 	VaryingColor = gammaCorrectColor(VertexColor) * ConstantColor;
-	updatePointSize();
+	setPointSize();
 	love_Position = position(TransformProjectionMatrix, VertexPosition);
 }]],
 }

+ 8 - 0
src/modules/math/wrap_Transform.cpp

@@ -57,6 +57,13 @@ int w_Transform_apply(lua_State *L)
 	return 1;
 }
 
+int w_Transform_isAffine2DTransform(lua_State *L)
+{
+	Transform *t = luax_checktransform(L, 1);
+	luax_pushboolean(L, t->getMatrix().isAffine2DTransform());
+	return 1;
+}
+
 int w_Transform_translate(lua_State *L)
 {
 	Transform *t = luax_checktransform(L, 1);
@@ -284,6 +291,7 @@ static const luaL_Reg functions[] =
 	{ "clone", w_Transform_clone },
 	{ "inverse", w_Transform_inverse },
 	{ "apply", w_Transform_apply },
+	{ "isAffine2DTransform", w_Transform_isAffine2DTransform },
 	{ "translate", w_Transform_translate },
 	{ "rotate", w_Transform_rotate },
 	{ "scale", w_Transform_scale },