Screen glitching in OS X Metal app? Error (IOAF code 1)? - macos

I'm making an app on OS X Sierra using Metal. Something I am doing is causing the screen to start glitching badly, flashing black in various places, which quickly escalates to the entire screen going black.
In XCode, if I use the GPU frame capture, the paused frame appears correct however -- it suddenly returns from the black abyss. I don't see any errors or warnings in the GPU frame information. However, I am relatively new to Metal and am not experienced with the frame debugger, so I may not know what to look for.
Usually there is nothing printed to the console, but occasionally I do get one of these:
Execution of the command buffer was aborted due to an error during execution. Internal Error (IOAF code 1)
The same app runs on iOS devices without this problem -- so far it only happens on OS X. Does this sound familiar? Any suggestions on what I should check?
I can post some code if it will be helpful, but right now I'm not sure what part of the program is the problem.
EDIT: In response to Noah Witherspoon -- it seems that the problem is caused by some kind of interaction between my scene drawing and the UI drawing. If I display only my scene, which is composed of fat, fuzzy lines, then the problem does not occur. It also does not occur if I display only the UI, which is orthographic projection, a bunch of rounded rectangles and some type. The problem happens only when both are showing. This is a lot of code, many buffers and a lot of commandBuffer usage, too much to put into a post. But here is a little bit.
My lines are rendered with vertex buffers which are arrays of floats, four per vertex:
let dataSize = count * 4 * MemoryLayout<Float>.size
vertexBuffer = device.makeBuffer(bytes: points, length: dataSize, options: MTLResourceOptions())!
These are rendered like this:
renderEncoder.setVertexBuffer(self.vertexBuffer, offset: 0, index: 0)
renderEncoder.setRenderPipelineState(strokeNode.strokePipelineState)
renderEncoder.drawPrimitives(type: .triangleStrip, vertexStart: 0, vertexCount: Int(widthCountEdge.count)*2-4)
renderEncoder.setRenderPipelineState(strokeNode.capPipelineState)
renderEncoder.drawPrimitives(type: .triangle, vertexStart: 0, vertexCount: 12)
Here's my main loop for drawing with the command Buffer.
if let commandBuffer = commandQueue.makeCommandBuffer() {
commandBuffer.addCompletedHandler { (commandBuffer) -> Void in
self.strokeNode.bufferProvider.availableResourcesSemaphore.signal()
}
self.updateDynamicBufferState()
self.updateGameState(timeInterval)
let renderPassDescriptor = view.currentRenderPassDescriptor
renderPassDescriptor?.colorAttachments[0].loadAction = .clear
renderPassDescriptor?.colorAttachments[0].clearColor = MTLClearColor(red: 0.0, green: 0.0, blue: 0.0, alpha: 0.0)
renderPassDescriptor?.colorAttachments[0].storeAction = .store
if let renderPassDescriptor = renderPassDescriptor, let renderEncoder = commandBuffer.makeRenderCommandEncoder(descriptor: renderPassDescriptor) {
strokeNode.subrender(renderEncoder, parentModelViewMatrix: viewMatrix, projectionMatrix: projectionMatrix, renderer:self)
mainscreen.draw(renderEncoder);
renderEncoder.endEncoding()
if let drawable = view.currentDrawable {
commandBuffer.present(drawable)
}
}
commandBuffer.commit()
}
The line drawing happens in strokeNode.subrender, and then my UI drawing happens in mainscreen.draw. The UI drawing has a lot of components - a lot to list here -- but I will try taking them out one by one and see if I can narrow it down. If none of this looks problematic I'll edit and post some of that ...
Thanks!

Related

Huge memory leak using NSImage.lockFocus()

I've written a small utility to generate character glyphs as image files in order to train a CoreML image classifier. This means thousands of images. It seems to track to NSImage.lockFocus(). This method allocates offscreen and draws offscreen then caches the result. I never need the image after I create the jpg file, but I can not seem to clear the cache. This seems to be an old problem, but a search turned up no working solution was found. Is there another way to avoid caching or to force a clear? Here is one of the problem methods.
var imageInProgress = NSImage()
func makeNSImage(input:String) {
let size = CGSize(width: 399, height: 399)
// select a random font
let selAttribIndex = Int.random(in: 0...attrArray.count-1)
let attribInput = NSAttributedString(string: input, attributes: attrArray[selAttribIndex])
let boundingRect = attribInput.boundingRect(with: size, options: [])
let startX = (size.width/2 - boundingRect.width/2)
let startY = (size.height/2 - boundingRect.height/2)
imageInProgress = NSImage(size: CGSize(width: 400, height: 400))
imageInProgress.lockFocus()
imageInProgress.backgroundColor = NSColor.white
attribInput.draw(at: CGPoint(x: startX, y: startY))
imageInProgress.unlockFocus()
}
This routine generates a root image and I then make N augmented versions. When I lock focus to draw the symbol, the app's memory allocation jumps 5 Meg, the unlock does not give it back. I call lockFocus many times during the creation of the augments and each time the app memory allocation climbs steadily until it crumps at more than 130 Gig!
Further digging reveals that NSImage and other swift wrapped Objective C objects do not all get released by the inherent ARC in Swift! In the case of NSImage, even recache() does not do it.
The solution is to wrap the code of my main loop with an autoreleasepool {}
See Is it necessary to use autoreleasepool in a Swift program?

SpriteKit PhysicsBody: Could not create physics body for basic shape

I have an extremely basic polygon that is the texture for a sprite in my game, yet when I try and create a physicsBody from this texture for the sprite I get this error:
2016-06-19 08:25:21.707 Space Escape[14677:5651144] PhysicsBody: Could not create physics body.
Also, the game uses many different simple polygons and for some the physicsBody can be created, yet for others it gets an error.
func setPhysics(size: CGSize) {
self.physicsBody = SKPhysicsBody(texture: asteroidTexture, size: size)
self.physicsBody?.angularDamping = 0
self.physicsBody?.angularVelocity = 2
}
Here is the texture:
In my playground it is working. Try replacing the size parameter as in the code below and let me know
let asteroidTexture = SKTexture(imageNamed: "sprite")
let physicsBody = SKPhysicsBody(texture: asteroidTexture, size: asteroidTexture.size())
I've experimented that this kind of physical representation could be decelerate your collisions. Instead of it, if you don't require extreme precision to the physical bodies of your sprites try to use:
self.physicsBody = SKPhysicsBody(circleOfRadius: size.width/2)
It is much lighter and slimmer for the cpu calculations.
You can see the big difference when your game is almost completed (for example 80%). I hope this helps.

Accelerated canvas context translation: bug, or my mistake?

I found an odd behavior while working on my pet game. I wanted to draw few objects on canvas, some of them required image / icon to be rotated. It is quite common use case, usual solution is to make use of context's rotate method. Going with the blow I used also translate to nicely and consistently put images in desired place.
This worked fine, until I tried Chrome on Windows laptop, with hardware acceleration enabled. Images started to blink and teleport across the screen. I found that it is related to acceleration (turning off accelerated graphics fixes problem) and my best guess is that when updating frame the renderer assumes that drawing calls are independent and can be executed in parallel. When context transforms take place it is not the case because context state changes.
Example of undesired behavior: having a canvas element with ID 'screen' try the following:
var canvas = document.getElementById("screen"),
ctx = canvas.getContext("2d");
var drawrect = function () {
ctx.fillStyle = this.color;
ctx.translate(this.x+10, this.y+10);
ctx.rotate(this.rotation);
ctx.fillRect(-10, -10, 20, 20);
ctx.rotate(-this.rotation);
ctx.translate(-this.x-10, -this.y-10);
};
var red = {
x: 22,
y: 22,
rotation: 0,
color: "#ff0000",
draw: drawrect
};
var blu = {
x: 22,
y: 111,
rotation: 0,
color: "#0000ff",
draw: drawrect
};
function main_loop() {
ctx.clearRect(0, 0, 450, 450);
frameId = requestAnimationFrame(main_loop);
red.draw();
red.x += 1;
red.rotation +=0.1;
blu.draw();
blu.x += 1;
blu.rotation -=0.1;
}
main_loop();
Working example: http://jsfiddle.net/1u2d7uhr/7/ (tested on Chrome, Chromium, Firefox; accelerated Chrome glitches, others do not)
I was able to 'fix' this by removing translations and rendering rotating elements to separate canvas, which is then (after rotations) drawn onto the main one. This seems hackish to me though.
Is it code error on my part?
In this case what is the right way to render rotations (perhaps with this question I should go do codereview, but I'm not sure if this is the case)?
Or is it buggy behavior on browser side? I understand the logic behind it but it can be very much surprising (and cause some confusion) to developers. Or am I only one...

Parallax Scrolling SpriteKit

I have found a tutorial on parallax scrolling in spritekit using objective-C though I have been trying to port it to swift without much success, very little in fact.
Parallax Scrolling
Does anyone have any other tutorials or methods of doing parallax scrolling in swift.
This is a SUPER simple way of starting a parallax background. WITH SKACTIONS! I am hoping it helps you understand the basics before moving to a harder but more effective way of coding this.
So I'll start with the code that get a background moving and then you try duplicating the code for the foreground or objects you want to put in your scene.
//declare ground picture. If Your putting this image over the top of another image (use a png file).
var groundImage = SKTexture(imageNamed: "background.jpg")
//make your SKActions that will move the image across the screen. this one goes from right to left.
var moveBackground = SKAction.moveByX(-groundImage.size().width, y: 0, duration: NSTimeInterval(0.01 * groundImage.size().width))
//This resets the image to begin again on the right side.
var resetBackGround = SKAction.moveByX(groundImage.size().width, y: 0, duration: 0.0)
//this moves the image run forever and put the action in the correct sequence.
var moveBackgoundForever = SKAction.repeatActionForever(SKAction.sequence([moveBackground, resetBackGround]))
//then run a for loop to make the images line up end to end.
for var i:CGFloat = 0; i<2 + self.frame.size.width / (groundImage.size().width); ++i {
var sprite = SKSpriteNode(texture: groundImage)
sprite.position = CGPointMake(i * sprite.size.width, sprite.size.height / 2)
sprite.runAction(moveBackgoundForever)
self.addChild(sprite)
}
}
//once this is done repeat for a forground or other items but them run at a different speed.
/*make sure your pictures line up visually end to end. Just duplicating this code will NOT work as you will see but it is a starting point. hint. if your using items like simple obstructions then using actions to spawns a function that creates that obstruction maybe a good way to go too. If there are more then two separate parallax objects then using an array for those objects would help performance. There are many ways to handle this so my point is simple: If you can't port it from ObjectiveC then rethink it in Swift. Good luck!

How to draw a new line on Gtk::DrawingArea area, while peristing previous lines that have already been drawn?

I am using C++11 with GNU tool chain with gtkmm3, on Ubuntu 12.04 LTS 32 bit.
I have been playing wtih some of the examples for gtkmm3 in Programming with gtkmm 3.
Based on 17.2.1.Example there, I inherited from Gtk::DrawingArea (MyDrawingArea here) and overrode the on_draw() event handler as follows:
MyDrawingArea.hpp
...
protected:
bool on_draw ( const Cairo::RefPtr<Cairo::Context>& cr ) override;
MyDrawingArea.cpp
bool MyDrawingArea::on_draw( const Cairo::RefPtr<Cairo::Context>& cr )
{
Gtk::Allocation allocation = get_allocation( );
const int width = allocation.get_width( );
const int height = allocation.get_height( );
int coord1{ height - 3 };
cr->set_line_width( 3.0 );
this->get_window( )->freeze_updates( );
cr->set_source_rgb( 0, 0.40, 0.60 );
cr->move_to( 0, coord1 );
cr->line_to( width, coord1 );
cr->stroke( );
cr->set_source_rgb( 1, 0.05, 1 );
cr->move_to( mXStart, coord1 );
cr->line_to( mXStart, mYAxis * 1.5 );
cr->show_text( to_string( mYAxis ) );
cr->stroke( );
mXStart += 5;
this->get_window( )->thaw_updates( );
return true;
}
My goal is to draw a simple bar graph based on a calculation I do in a little test application, the idea being that each time the on_draw() event is called, the next bar would be moved 5 units to the right on mXAxis and a vertical line would be drawn based on the new mYaxis value, which is computed based on the results of the new calculation.
When I want to repaint my graph and trigger the MyDrawingArea::on_draw() event, I call MyDrawingArea.show_all() from my application after the calculation has completed, and new x and y axes have been set.
However, this does not work as I expected: MyDrawingArea.show_all() invalidates the entire drawing window and draws from scratch: the new graph line appears in its proper place, but the previous ones are erased. I also tried MyDrawingArea.queue_draw(), which had the same effect. But I want to persist the previous graph results so I can get a profile of the calculation results, as I calculate with different values.
This implementation is also causing the bottom line on my graph (my x axis on the graph)- drawn by the first stroke() call in my code example, to be rendered anew on each call to on_draw() - although this should not be necassary since this line persists for the lifetime of MyDrawingArea - it should not be necessary to invalidate and then re-draw it on each new on_draw() event, as my code is currently doing, because I am haven't yet found a way to handle this.
I am very new to Cairo, so I'm sure I'm probably doing this completely wrong, but explicit, task-oriented documentation appears to be sparse - have not found anything that explains how to do this, although I'm sure it is quite simple.
What do I need to do to draw a new line on Gtk::DrawingArea, while persisting previous graph lines that have already been drawn on previous passes, and establish graphics elements that will persist for the lifetime of the Gtk::DrawingArea widget. Obviously using show_all() or queue_draw() and doing it all in the on_draw() event is not the way to go.
In general, you must draw the entire widget and Cairo will clip the drawing to the predefined dirty region. See also GTK reference manual for the "GtkWidget::draw" signal for performance tips:
The signal handler will get a cr with a clip region already set to the
widget's dirty region, i.e. to the area that needs repainting.
Complicated widgets that want to avoid redrawing themselves completely
can get the full extents of the clip region with
gdk_cairo_get_clip_rectangle(), or they can get a finer-grained
representation of the dirty region with
cairo_copy_clip_rectangle_list().
So you may be able to redraw only the region you want with gtk_widget_queue_draw_area().

Resources