I tried to use asm for BCI and i have a requirement where i am supposed to inject "if condition" ,so i tried using something like below
Below is the code snippet..if i comment the jump instruction things work fine..with jump instruction i see verifyerror
#Override
protected void onMethodEnter() {
try{
visitor.visitVarInsn(ALOAD, 0);
visitor.visitFieldInsn(GETFIELD, "com/vish/MyWrapper", "isCached", "Z");
Label jump = new Label();
visitor.visitJumpInsn(IFEQ,jump);
visitor.visitMethodInsn(Opcodes.INVOKESTATIC, MyConstants.TO_HELPER_CLASS, "sayHello","(Z)V");
visitor.visitVarInsn(ALOAD, 0);
visitor.visitInsn(ICONST_1);
visitFieldInsn(PUTFIELD, "com/vish/MyWrapper", "isCached", "Z");
visitor.visitLabel(jump);
visitor.visitVarInsn(ALOAD, 0);
visitor.visitFieldInsn(GETFIELD, "com/vish/MyWrapper", "isCached", "Z");
visitor.visitMethodInsn(Opcodes.INVOKESTATIC, MyConstants.TO_HELPER_CLASS, "sayHello",
"()V");
}catch(Exception e){
e.printStackTrace();
}
}
but when i try to run i get the below exception
java.lang.VerifyError: JVMVRFY036 stack underflow; class=com/vish/MyWrapper, method=service()V, pc=10
at java.lang.J9VMInternals.verifyImpl(Native Method)
at java.lang.J9VMInternals.verify(J9VMInternals.java:72)
at java.lang.J9VMInternals.verify(J9VMInternals.java:70)
at java.lang.J9VMInternals.initialize(J9VMInternals.java:134)
If i comment the jump instruction things work fine.
I did some reading and came to know that there is a possibility of messing of stack map frames because of the use of JumpInstructions and also read that using of COMPUTE_FRAMES options along with SKIP_FRAMES will result in in automatic computing of stack map frames
"public static final int COMPUTE_FRAMES
Flag to automatically compute the stack map frames of methods from scratch. If this flag is set, then the calls to the MethodVisitor.visitFrame(int, int, java.lang.Object[], int, java.lang.Object[]) method are ignored, and the stack map frames are recomputed from the methods bytecode. The arguments of the visitMaxs method are also ignored and recomputed from the bytecode. In other words, computeFrames implies computeMaxs."
can any one shed some light on what wrong am i doing..do i still need to compute stack map frames in case of Jump instructions?If its the case can a i get sample somewhere of how stack map frames can be computed??
Thanks
The instruction introduced here:
visitor.visitMethodInsn(Opcodes.INVOKESTATIC, MyConstants.TO_HELPER_CLASS, "sayHello","(Z)V");
...requires a boolean (integer) parameter on the stack. If the IFEQ is there, the stack is empty. If you comment out the IFEQ, the stack has the parameter. The stack underflow is caused by calling the method without the necessary parameter on the stack. This has nothing to do with stack frame maps.
The problem is that you're missing the argument for the first sayHello. If you want to pass the result of getCached you need to add another visitor.visitFieldInsn(GETFIELD, "com/vish/MyWrapper", "isCached", "Z"); before it.
Assuming this is what was intended, the code should be something like
visitor.visitVarInsn(ALOAD, 0);
visitor.visitFieldInsn(GETFIELD, "com/vish/MyWrapper", "isCached", "Z");
Label jump = new Label();
visitor.visitJumpInsn(IFEQ,jump);
visitor.visitFieldInsn(GETFIELD, "com/vish/MyWrapper", "isCached", "Z");
visitor.visitMethodInsn(Opcodes.INVOKESTATIC, MyConstants.TO_HELPER_CLASS, "sayHello","(Z)V");
visitor.visitVarInsn(ALOAD, 0);
visitor.visitInsn(ICONST_1);
visitFieldInsn(PUTFIELD, "com/vish/MyWrapper", "isCached", "Z");
visitor.visitLabel(jump);
visitor.visitVarInsn(ALOAD, 0);
visitor.visitFieldInsn(GETFIELD, "com/vish/MyWrapper", "isCached", "Z");
visitor.visitMethodInsn(Opcodes.INVOKESTATIC, MyConstants.TO_HELPER_CLASS, "sayHello",
"()V");
Related
I'm altering someone else's code. They used PNG's which are loaded via BufferedImage. I need to load a TGA instead, which is just simply a 18 byte header and BGR codes. I have the textures loaded and running, but I get a gray box instead of the texture. I don't even know how to DEBUG this.
Textures are loaded in a ByteBuffer:
final static int datasize = (WIDTH*HEIGHT*3) *2; // Double buffer size for OpenGL // not +18 no header
static ByteBuffer buffer = ByteBuffer.allocateDirect(datasize);
FileInputStream fin = new FileInputStream("/Volumes/RAMDisk/shot00021.tga");
FileChannel inc = fin.getChannel();
inc.position(18); // skip header
buffer.clear(); // prepare for read
int ret = inc.read(buffer);
fin.close();
I've followed this: [how-to-manage-memory-with-texture-in-opengl][1] ... because I am updating the texture once per frame, like video.
Called once:
GL11.glBindTexture(GL11.GL_TEXTURE_2D, textureID);
GL11.glTexParameteri(GL11.GL_TEXTURE_2D, GL11.GL_TEXTURE_WRAP_S, GL11.GL_CLAMP);
GL11.glTexParameteri(GL11.GL_TEXTURE_2D, GL11.GL_TEXTURE_WRAP_T, GL11.GL_CLAMP);
GL11.glTexParameteri(GL11.GL_TEXTURE_2D, GL11.GL_TEXTURE_MAG_FILTER, GL11.GL_NEAREST);
GL11.glTexParameteri(GL11.GL_TEXTURE_2D, GL11.GL_TEXTURE_MIN_FILTER, GL11.GL_NEAREST);
GL11.glTexImage2D(GL11.GL_TEXTURE_2D, 0, GL11.GL_RGB, width, height, 0, GL11.GL_RGB, GL11.GL_UNSIGNED_BYTE, (ByteBuffer) null);
assert(GL11.GL_NO_ERROR == GL11.glGetError());
Called repeatedly:
GL11.glBindTexture(GL11.GL_TEXTURE_2D, textureID);
GL11.glTexSubImage2D(GL11.GL_TEXTURE_2D, 0, 0, 0, width, height, GL11.GL_RGB, GL11.GL_UNSIGNED_BYTE, byteBuffer);
assert(GL11.GL_NO_ERROR == GL11.glGetError());
return textureID;
The render code hasn't changed and is based on:
GL11.glDrawArrays(GL11.GL_TRIANGLES, 0, this.vertexCount);
Make sure you set the texture sampling mode. Especially min filter: glTexParameteri ( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR). The default setting is mip mapped (GL_NEAREST_MIPMAP_LINEAR) so unless you upload mip maps you will get a white read result.
So either set the texture to no mip or generate them. One way to do that is to call glGenerateMipmap after the tex img call.
(see https://www.khronos.org/opengles/sdk/docs/man/xhtml/glTexParameter.xml).
It's a very common gl pitfall and something people just tend to know after getting bitten by it a few times.
There is no easy way to debug stuff like this. There are good gl debugging tools in for example xcode but they will not tell you about this case.
Debugging GPU code is always a hassle. I would bet my money on a big industry progress in this area as more companies discover the power of GPU. Until then; I'll share my two best GPU debugging friends:
1) Define a function to print OGL errors:
int printOglError(const char *file, int line)
{
/* Returns 1 if an OpenGL error occurred, 0 otherwise. */
GLenum glErr;
int retCode = 0;
glErr = glGetError();
while (glErr != GL_NO_ERROR) {
printf("glError in file %s # line %d: %s\n", file, line, gluErrorString(glErr));
retCode = 1;
glErr = glGetError();
}
return retCode;
}
#define printOpenGLError() printOglError(__FILE__, __LINE__)
And call it after your render draw calls (possible earlier errors will also show up):
GL11.glDrawArrays(GL11.GL_TRIANGLES, 0, this.vertexCount);
printOpenGLError();
This alerts if you make some invalid operations (which might just be your case) but you usually have to find where the error occurs by trial and error.
2) Check out gDEBugger, free software with tons of GPU memory information.
[Edit]:
I would also recommend using the opensource lib DevIL - its quite competent in loading various image formats.
Thanks to Felix, by not calling glTexSubImage2D (leaving the memory valid, but uninitialized) I noticed a remnant pattern left by the default memory. This indicated that the texture is being displayed, but the load is most likely the problem.
**UPDATE:
The, problem with the code above is essentially the buffer. The buffer is 1024*1024, but it is only partially filled in by the read, leaving the limit marker of the ByteBuffer at 2359296(1024*768*3) instead of 3145728(1024*1024*3). This gives the error:
Number of remaining buffer elements is must be ... at least ...
I thought that OpenGL needed space to return data, so I doubled the size of the buffer.
The buffer size is doubled to compensate for the error.
final static int datasize = (WIDTH*HEIGHT*3) *2; // Double buffer size for OpenGL // not +18 no header
This is wrong, what is needed is the flip() function (Big THANKS to Reto Koradi for the small hint to the buffer rewind) to put the ByteBuffer in read mode. Since the buffer is only semi-full, the OpenGL buffer check gives an error. The correct thing to do is not double the buffer size; use buffer.position(buffer.capacity()) to fill the buffer before doing a flip().
final static int datasize = (WIDTH*HEIGHT*3); // not +18 no header
buffer.clear(); // prepare for read
int ret = inc.read(buffer);
fin.close();
buffer.position(buffer.capacity()); // make sure buffer is completely FILLED!
buffer.flip(); // flip buffer to read mode
To figure this out, it is helpful to hardcode the memory of the buffer to make sure the OpenGL calls are working, isolating the load problem. Then when the OpenGL calls are correct, concentrate on the loading of the buffer. As suggested by Felix K, it is good to make sure one texture has been drawn correctly before calling glTexSubImage2D repeatedly.
Some ideas which might cause the issue:
Your texture is disposed somewhere. I don't know the whole code but I guess somewhere there is a glDeleteTextures and this could cause some issues if called at the wrong time.
Are the texture width and height powers of two? If not this might be an issue depending on your hardware. Old hardware sometimes won't support non-power of two images.
The texture parameters changed between the draw calls at some other point ( Make a debug check of the parameters with glGetTexParameter ).
There could be a loading issue when loading the next image ( edit: or even the first image ). Check if the first image is displayed without loading the next images. If so it must be one of the cases above.
If I create 2 separate mappings of the same file in the same process will the pointers be shared?
in other words:
LPCTSTR filename = //...
HANDLE file1 = CreateFile(filename, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, 0);
HANDLE fileMapping1 = CreateFileMapping(file1, NULL, PAGE_READONLY, 0, 0, 0);
void* pointer1 = MapViewOfFile(fileMapping1, FILE_MAP_READ, 0, 0, 0);
CloseHandle(fileMapping1);
CloseHandle(file1);
HANDLE file2 = CreateFile(filename, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, 0);
HANDLE fileMapping2 = CreateFileMapping(file2, NULL, PAGE_READONLY, 0, 0, 0);
void* pointer2 = MapViewOfFile(fileMapping2, FILE_MAP_READ, 0, 0, 0);
CloseHandle(fileMapping2);
CloseHandle(file2);
Will pointer1 ever be equal to pointer2?
The reason I am asking is that I have several threads that need to search in a large (300+MB) file and I want to use memory mapping for that. However the process needs to be able to run on an old 32bit xp machine, so if each thread allocated their own copy in virtual memory then I could run out of memory.
msdn has documented it between the lines:
As mentioned above, you can have multiple views of the same
memory-mapped file, and they can overlap. But what about mapping two
identical views of the same memory-mapped file? After learning how to
unmap a view of a file, you could come to the conclusion that it would
not be possible to have two identical views in a single process
because their base address would be the same, and you wouldn't be able
to distinguish between them. This is not true. Remember that the base
address returned by either the MapViewOfFile or the MapViewOfFileEx
function is not the base address of the file view. Rather, it is the
base address in your process where the view begins. So mapping two
identical views of the same memory-mapped file will produce two views
having different base addresses, but nonetheless identical views of
the same portion of the memory-mapped file.
Also:
The point of this little exercise is to emphasize that every view of a
single memory-mapped file object is always mapped to a unique range of
addresses in the process. The base address will be different for each
view. For that reason the base address of a mapped view is all that is
required to unmap the view.
Will pointer1 ever be equal to pointer2?
The pointers might be the equal in case MapViewOfFile chooses the same address for the mapping. You don't control this with MapViewOfFile, and you have some control over this with MapViewOfFileEx (last argument lpBaseAddress there).
Each separate MapViewOfFile can create a new mapping over the same physical data, so OS does not need to map the file mapping into the same addresses even if you open two mappings simultaneously, preserving the coherence of data. It is easy to see this by modifying your code slightly:
HANDLE file1 = CreateFile(filename, GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, 0, NULL);
HANDLE fileMapping1 = CreateFileMapping(file1, NULL, PAGE_READWRITE, 0, 0, 0);
void* pointer1 = MapViewOfFile(fileMapping1, FILE_MAP_READ | FILE_MAP_WRITE, 0, 0, 0);
//CloseHandle(fileMapping1);
//CloseHandle(file1);
HANDLE file2 = CreateFile(filename, GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, 0, NULL);
HANDLE fileMapping2 = CreateFileMapping(file2, NULL, PAGE_READWRITE, 0, 0, 0);
void* pointer2 = MapViewOfFile(fileMapping2, FILE_MAP_READ | FILE_MAP_WRITE, 0, 0, 0);
INT& n1 = *((INT*) pointer1);
INT& n2 = *((INT*) pointer2);
ATLASSERT(&n1 != &n2); // The pointers are not equal even though they point
// the same data!
INT n3 = 0;
n1 = 2;
n3 += n2;
n1 = 3;
n3 += n2;
ATLASSERT(n3 == 5); // That's 2+3 we wrote through n1 and read through n2
//CloseHandle(fileMapping2);
//CloseHandle(file2);
That is, pointer equivalence is not something you should expect or rely on. Especially if your mapping is large, and reopening does not take place immediately.
MapViewOfFile finds a hole in your process's address space that is big enough for the entire file. I would not expect it to return the same pointer even if you passed the same file mapping object twice. For different mapping objects and different file handles, I would definitely expect the pointers to be different.
Behind the scenes, Windows should be using the same 'section' object, so both ranges of virtual address space should be mapped to the same physical memory. This is the same as two processes mapping the same file.
To use the same memory range from both threads, one thread will have to map the file and store the pointer in a shared location. The other thread will have to retrieve that pointer from the shared location. You're likely to need reference counting to decide when to unmap the file (which you do by calling UnmapViewOfFile - closing the file mapping handle will not release that address space).
The same physical memory will be used, but the two pointers will likely not be the same. In any case, you have no guarantee that they will be the same, even if they incidentially are when you test. Read as: you cannot ever rely on the assumption that this will be the case.
You are creating two mappings on two different file handles. Incidentially they refer to the same file (which is why the same physical memory will be used), but they are still two different mappings that do not logically relate to each other in any way.
Yes, it may sound illogical and unreasonable (maybe even impossible) to have the same physical memory at two different addresses. However, this is a perfectly legitimate thing.
Currently I am attempting to use PBOs to get video data to textures. I'm not sure if what I'm trying to do is even possible, or a good way to do it if it IS possible... I have 3 textures with the GL_RED format (one for each channel, not using Alpha currently). All three of these will be filled out in a single call to an external library.
Here's binding the buffer, etc:
void LockTexture(const TextureID& id, void ** ppbData)
{
Texture& tex = textures.getArray()[id];
glBindBuffer(GL_PIXEL_UNPACK_BUFFER, tex.glBufID);
glBufferData(GL_PIXEL_UNPACK_BUFFER, tex.width * tex.height, NULL, GL_STREAM_DRAW);
*ppbData = glMapBuffer(GL_PIXEL_UNPACK_BUFFER, GL_WRITE_ONLY);
}
This is done for the 3 textures, the buffers are then filled by the external library. Then I attempt to push them to the texture, like so:
void UnlockTexture(const TextureID& id)
{
Texture& tex = textures.getArray()[id];
glUnmapBuffer(GL_PIXEL_UNPACK_BUFFER);
glBindTexture(tex.glTarget, tex.glTexID);
glCheckForErrors(); // <--- NO ERROR
glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, tex.width, tex.height, GL_RED, GL_UNSIGNED_BYTE, 0);
glCheckForErrors(); // <--- ERROR
glBindBuffer(GL_PIXEL_UNPACK_BUFFER, 0);
glBindTexture(tex.glTarget, 0);
}
Going through the list of reasons the error could be generated, this is what I know:
texture array has been defined
type is correct
data param (offset) is good at 0
not executed between glBegin/glEnd
This one I'm not sure about:
error is generated if a non-zero buffer object name is bound to the GL_PIXEL_UNPACK_BUFFER target and the data would be unpacked from the buffer object such that the memory reads required would exceed the data store size.
This one seems like it could be an issue, but I'd have no idea how else to handle this:
error is generated if a non-zero buffer object name is bound to the GL_PIXEL_UNPACK_BUFFER target and the buffer object's data store is currently mapped.
Am I correct in saying that this glUnmapBuffer is unmapping the last-mapped buffer, so the correct buffer is still mapped?
GL version is 3.2
I would greatly appreciate any help on this one, thanks!
glUnmapBuffer(target) will unmap the buffer which is currently bound to target. From the code you posted, it is unclear if there will still be the same binding as at the time you did the map call. Your wordings suggests that you do the mapping for all 3 right after each other, and when you try to unmap it, you only unmap the last one mapped because you forget to rebind the other ones, which would lead to this error for the first two of your textures.
I was just shocked to learn that inserting in a tree view is much faster with TVI_FIRST than TVI_LAST.
By contrast, deletion is slower -- my program exits a lot more slowly when I use it.
Why is this?!
bracket your code with this:
SendMessage(hWnd, WM_SETREDRAW, FALSE, 0);
///////
....
SendMessage(hWnd, WM_SETREDRAW, TRUE, 0);
It's the redraw that's slow.
I can't figure this one out. If I click on a textbox, it sets up a timer to fire x number of times a minute. The timer seems to work fine, but the lower the cycles per minute, the lower the volume that the sound affect plays. I must not be understanding how the XNA framework works.
private System.Threading.Timer tmrMetronome_m;
private void tbTempo_MouseLeftButtonDown(object sender, MouseButtonEventArgs e)
{
TextBlock tb = (TextBlock)sender;
int iBeatsPerMinute = int.Parse(tb.Text);
int iMS = 1000 * 60 / iBeatsPerMinute;
if (this.tmrMetronome_m != null)
{
this.tmrMetronome_m.Change(new TimeSpan(0), new TimeSpan(0, 0, 0, 0, iMS));
}
else
{
this.tmrMetronome_m = new System.Threading.Timer(MetronomeTick, null, new TimeSpan(0), new TimeSpan(0, 0, 0, 0, iMS));
}
}
private void MetronomeTick(object state)
{
using (System.IO.Stream strWAV = TitleContainer.OpenStream("wav/Beat.wav"))
{
SoundEffect effect = SoundEffect.FromStream(strWAV);
FrameworkDispatcher.Update();
effect.Play();
}
}
Are you sure there isn't some other issue at play here? Could the beats possibly be overlapping to create the impression of being louder when they occur more often?
I recreated pretty much your exact code above in a quick XNA project, and did not experience the loudness issue. I was not -- obviously -- using the same audio sample though.
You may want to try moving that Stream reading out to the initialization somewhere. Store the sound effect contents into a SoundEffect variable during your app loading time and then call Play() on this variable during the MetronomeTick.
Depending on your wants, an alternative is to only store a SoundEffectInstance variable, and then during load time, load it up like so:
using (System.IO.Stream strWAV = TitleContainer.OpenStream("wav/Beat.wav"))
{
SoundEffect effect = SoundEffect.FromStream(strWAV);
soundInstance = effect.CreateInstance();
}
To play it, just call Play() on the SoundEffectInstance object.
Of course, because you're only keeping one instance, two of these sounds will never overlap (not sure of what you want). Either way it's worth trying if this problem still persists.