Convert BGR to RGB in Texture2D from unmanaged memory

I’m trying to use the Chromium Embedded Framework inside of MonoGame (via CefGlue), so I can create a HTML/CSS based UI. I actually have pretty much everything I want working, but there’s an issue I’m not sure how to deal with.

Any colours I specify are displayed with RGB inverted to BGR - ie, #FF0000 or rgb(255,0,0) will be represented as blue when it should be red, and vice versa. Having not done any graphics dev to speak of prior to now, I’m a bit stuck.

Incidentally, this same bug exists in MonoCef, which handles the texture copy in a slightly more complex but fundamentally similar way to my code.

Here’s some code showing how I’m creating my Texture2D from Cef’s frame buffer:

byte[] managedArray = new byte[width * height * 4];

// Note: buffer is an IntPtr coming from CefGlue, pointing to memory containing the rendered UI
Marshal.Copy(buffer, managedArray, 0, width * height * 4);                

Texture2D uiTexture = new Texture2D(GraphicsDevice, width, height);                
uiTexture.SetData(managedArray);
this._UITexture = uiTexture;

Basically, I’m looking for a way to either specify the format of the texture I’m sending in is the opposite of the way it’s currently read, or else somehow performantly switch all the colours, every frame, to be correct. Ideally there’s some API that I’m not aware of to specify how to read in this data, or something, but I’ve been unable to locate one.

Does anyone have any knowledge that could help me out here? Thanks.

Note: I’m trying to be as cross-platform friendly as possible, running on dotnet core (hence not using MonoCef, which depends on CefSharp), so would rather avoid any System.Drawing references, but if you only have an answer that does use System.Drawing, I’d still love to see one. Also, does anyone know of a way to avoid copying the texture data? It’d be way nicer to reference it directly from the IntPtr…

You could mod the array before setting it to your uiTexture to rearrange the R/B values.

Though the method I would recommend would be a simple shader. Here’s one that would swap the R/B values (happens at draw time).

(untested, but it’s quite simple so should be fine honestly)

#if OPENGL
	#define SV_POSITION POSITION
	#define VS_SHADERMODEL vs_3_0
	#define PS_SHADERMODEL ps_3_0
#else
	#define VS_SHADERMODEL vs_4_0 //_level_9_1
	#define PS_SHADERMODEL ps_4_0 //_level_9_1
#endif


Texture2D SpriteTexture;
sampler2D SpriteTextureSampler = sampler_state { Texture = <SpriteTexture>; };


struct VertexShaderOutput
{
	float4 Position : SV_POSITION;
	float4 Color : COLOR0;
	float2 TextureCoordinates : TEXCOORD0;
};


float4 MainPS(VertexShaderOutput input) : COLOR
{
	float4 color = tex2D(SpriteTextureSampler, input.TextureCoordinates);

	float rBuffer = color.r;
	color.r = color.b;
	color.b = rBuffer;

	return color;
}


technique SpriteDrawing
{
	pass P0
	{
		PixelShader = compile PS_SHADERMODEL MainPS();
	}
}

Put that in a “rbSwapShader.fx” file and add to your content builder, It can then be used like so:

shader = Content.Load<Effect>("rbSwapShader");

spriteBatch.Begin(
	sortMode: spriteSortMode,
	blendState: blendState ?? BlendState.AlphaBlend,
	effect: shader
);
1 Like

That works beautifully. Thank you very much!

1 Like