Sign in to follow this  
MysteryX

Access Violation Errors

Recommended Posts

I have this code that processes memory video frames through HLSL pixel shaders and DirectX 9. There is no graphical interface, it is a DLL that runs within a video processing chain.
https://github.com/mysteryx93/AviSynthShader/blob/master/Src/D3D9RenderImpl.cpp

It is working. Most of the time.

Sometimes, when starting it, it fails with "Access Violation Error". I was having success loading the script chain within Windows Media Player, and then it would fail within MPC-HC, and sometimes it works. I really don't understand the logic of when it works and when it doesn't, and it seems to depend based on what program is loading the script chain.

Another thing I've seen is that running GPU-Z to monitor GPU usage is causing it to crash unexpectedly.

But once the script is loaded and running, it works and it is stable (unless I start GPU-Z).

Where could I look for the error? Changes to the device, perhaps?

I'm not seeing any error when running it through the debugger so it's hard to see where it is crashing.

Edit: Right after posting this, the script crashed half-way through after running stable for an hour.

Edit2: Actually, there is one way to see the error in the debugger, since GPU-Z causes it to crash consistently. After starting GPU-Z, m_pDevice->TestCooperativeLevel() fails.

Edit3: TestCooperationLevel() returns D3DERR_DEVICENOTRESET. and Device->Reset() returns 0x8876086c, not sure what error it represents. What's the right way of handling this? Edited by MysteryX

Share this post


Link to post
Share on other sites
That's a regular C++ memory error -- trying to read/write memory that your program doesn't own. Usually caused by uninitialised variables or bad memory management (e.g. continuing to use a pointer after it's been freed/released).

Double check you're initializing evry pointer to NULL. Turn on compiler warnings and fix them all.
Make sure you're checking the return value of every D3D function for errors, and handling them.
Often you can get access violations in D3D code by ignoring errors. E.g. If a "Create" function fails, but then you try and use the resulting pointer anyway.

As for debugging, you can add a crash handler to your DLL (google has a good open source one, I'll try find thr link...), or, if the access violation causes a modal dialog to appear, then go into visual-studio while that dialog is up, and use "Debug->Attach to process" to attach the debugger after the crash, and try and get a call-stack.

Share this post


Link to post
Share on other sites
HRESULT D3D9RenderImpl::SetPixelShader(LPCSTR pPixelShaderName, LPCSTR entryPoint, LPCSTR shaderModel, LPSTR* ppError)
{
	CComPtr<ID3DXBuffer> code;
	CComPtr<ID3DXBuffer> errMsg;

	HRESULT hr = D3DXCompileShaderFromFile(pPixelShaderName, NULL, NULL, entryPoint, shaderModel, 0, &code, &errMsg, &m_pPixelConstantTable);
	if (FAILED(hr)) {
		if (errMsg != NULL) {
			size_t len = errMsg->GetBufferSize() + 1;
			*ppError = new CHAR[len];
			memcpy(*ppError, errMsg->GetBufferPointer(), len);
		}
		return hr;
	}

	return m_pDevice->CreatePixelShader((DWORD*)code->GetBufferPointer(), &m_pPixelShader);
}

I've looked at it, and this seems problematic, because won't "*ppError = new CHAR[len];" be invalid/deconstructed right after the braces are exited, thus returning an invalid string?

	// The RenderTarget returns the previously generated scene for an unknown reason.
	// As a fix, we render another scene so that the previous scene becomes the one returned.
	HR(m_pDevice->BeginScene());
	HR(m_pDevice->EndScene());
	SCENE_HR(m_pDevice->DrawPrimitive(D3DPT_TRIANGLEFAN, 0, 2), m_pDevice);

Also, are you sure you need to do this "fix"? Seems a bit strange to Present() two times? And what vertex buffer etc. does that DrawPrimitive() depend on?

Share this post


Link to post
Share on other sites

Sounds like your device is in a lost state after creation and you are not handling it. Calling reset is not enough, there are additional steps required (like freeing all resources in the default pool). Check this article for more info: https://msdn.microsoft.com/en-us/library/windows/desktop/bb174714(v=vs.85).aspx

Welcome to the worst part of D3D9. Or if you don't care about Windows XP, just switch to D3D9Ex and forget about lost devices.

 

Share this post


Link to post
Share on other sites

Is it possible something has taken the device away?

 

It sounds like something isn't checking an error status after or before that point or even in the calling executable (its possible).

 

The error code appears to mean "there is no compatible device available".

 

Is it possible something else has an exclusive lock?

Share this post


Link to post
Share on other sites

I've looked at it, and this seems problematic, because won't "*ppError = new CHAR[len];" be invalid/deconstructed right after the braces are exited, thus returning an invalid string?

ppError isn't declared within those bracelets but is a function parameter.
 

Also, are you sure you need to do this "fix"? Seems a bit strange to Present() two times? And what vertex buffer etc. does that DrawPrimitive() depend on?

It's a bit strange and nobody gave me any explanation for it yet, but if I don't, then it returns the previously-generated frame instead of the frame that I just passed in. This hack works, and I have no idea why.
 

Sounds like your device is in a lost state after creation and you are not handling it. Calling reset is not enough, there are additional steps required (like freeing all resources in the default pool). Check this article for more info: https://msdn.microsoft.com/en-us/library/windows/desktop/bb174714(v=vs.85).aspx
Welcome to the worst part of D3D9. Or if you don't care about Windows XP, just switch to D3D9Ex and forget about lost devices.

Simply replacing IDirect3D9 with IDirect3D9Ex!? That's a solution I like! I tried it and it's working so far. I'll play around with it to see whether that solves it.

As for Windows XP, it's not supported anymore. I tried doing a clean install of Windows XP a while ago on an old computer, and before I could even finish downloading the drivers, it got hacked to the point where it wouldn't even boot anymore. Probably the infamous "DNS exploit" redirecting into some nasty virus. Since then, I consider Windows XP dead.

Thanks! Edited by MysteryX

Share this post


Link to post
Share on other sites
OK... the device lost problem is solved, but I still get the Access Violation error.

It happens "sometimes" when I'm running it in multi-threaded mode. I managed to get it to bug while running it through the debugger. It created 80 instances of the class and then crashed.

When opening it in VirtualDub, sometimes it said "Out of memory", so I though it might be going over the 2GB memory limit. I removed stuff from the script chain to ensure it doesn't go over the memory limit, and when opening it in MPC-HC, I still got an Access Violation error, although it doesn't seem to crash as much.


Perhaps I've been seeing 3 different errors
1. Device lost (solved)
2. Out of memory (can easily solve by removing stuff from the video script chain)
3. Access Violation Error

The Access Violation error is only happening in multi-threaded mode. Each thread is completely independent from each other. Since I run 8 threads, it creates 8 instances each time the piece of code is used in the script. Edited by MysteryX

Share this post


Link to post
Share on other sites
I've been running it and it has been stable.

I just had to lower the amount of threads from 8 to 4, which leaves my CPU at 80% instead of 100%, but it's all good.

I'm running a shader twice, with two passes each time, plus it takes other shader calls for each pass. There's at least 8-12 instances created *per thread*. 8 threads creates 64-96 instances and consume considerable memory. 4 threads cuts memory usage in half.

Share this post


Link to post
Share on other sites
argh... I just realized that each time this class is being created, it is creating 8 threads. Which means that if running with 8 threads and calling shaders 10 times, it creates 8 * 8 * 10 = 640 threads!!

My code doesn't have anything to create threads... is there something within the DirectX 9 API that could be creating those threads?


Edit: by debugging when I run a single instance, I see these threads. There is the main thread followed by 3 ntdll.dll, then 7x d3d9.dll each followed by 2 ntdll.dll

So these threads are created by DirectX 9 somehow.

Edit2: When creating the device, removing behavior flag D3DCREATE_MULTITHREADED and adding D3DCREATE_DISABLE_PSGP_THREADING slightly increases performance, but I still get all those threads created. However, when debugging, I'm not seeing all those extra d3d9.dll threads anymore; only when running it live.

Edit3: Actually, performance is better without the D3DCREATE_DISABLE_PSGP_THREADING flag, so perhaps all these threads is just the way DX9 optimizes itself and I have to leave it that way.

Edit4: This is a totally different issue, better create a separate conversation thread for this. Edited by MysteryX

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

Sign in to follow this