I will be very short:
I'am drawing lines using drawrect and NSBezierPath.
To draw these lines I am using a for loop.
Now, since the loop takes many seconds,I'm trying to use a NSProgresIndicator to show the progress and to update it within the loop I used dispatch_async & queue.. The ProgressIndicator updates but nothing is being drawn.. If don't use the queue the lines are drawn but the indicator updates at the end of the cycle.
What am I doing wrong ?
The error:
<Error>: CGContextRestoreGState: invalid context 0x0.
This is a serious error.
This application, or a library it uses, is using an invalid context
and is thereby
contributing to an overall degradation of system stability and reliability.
This notice is a courtesy: please fix this problem.
It will become a fatal error in an upcoming update.
// SAMPLE OF CODE
dispatch_queue_t myQueue = dispatch_queue_create("my queue", NULL);
dispatch_async(myQueue, ^
{
for (int i = 1; i <= 200; i++) {
dispatch_async(dispatch_get_main_queue(), ^{
[istance set_progress:i];
//This sets the progress, but bezierPath doesn't work
});
//Bezier already alloc & init
[my_path moveToPoint....]
[my_path lineToPoint....]
[my_path stroke]
}
});
In general you shouldn't be drawing on a background thread or queue.
Please read this document for information about multithreaded drawing. Skip to "Drawing Restrictions"
https://developer.apple.com/library/mac/documentation/Cocoa/Conceptual/Multithreading/ThreadSafetySummary/ThreadSafetySummary.html
Related
We have two different platform and with CPU frequency the same setting, and found the time cost of canvas->flush() on the rasterizer thread has huge difference at YT start time, the quick one only has 1.632ms at most time, and the slow one has 7.292ms at most time, so is there a way find the root cause of the difference and to optimize it?
cobalt version : Cobalt 11.132145 with ARM-Linux and Opengl
1.
2.Code of canvas->flush()
void HardwareRasterizer::Impl::Submit(
const scoped_refptr<render_tree::Node>& render_tree,
const scoped_refptr<backend::RenderTarget>& render_target,
const Options& options) {
DCHECK(thread_checker_.CalledOnValidThread());
scoped_refptr<backend::RenderTargetEGL> render_target_egl(
base::polymorphic_downcast<backend::RenderTargetEGL*>(
render_target.get()));
// Skip rendering if we lost the surface. This can happen just before suspend
// on Android, so now we're just waiting for the suspend to clean up.
if (render_target_egl->is_surface_bad()) {
return;
}
backend::GraphicsContextEGL::ScopedMakeCurrent scoped_make_current(
graphics_context_, render_target_egl);
// Make sure the render target's framebuffer is bound before continuing.
// Skia will usually do this, but it is possible for some render trees to
// have non-skia draw calls only, in which case this needs to be done.
GL_CALL(glBindFramebuffer(GL_FRAMEBUFFER,
render_target_egl->GetPlatformHandle()));
// First reset the graphics context state for the pending render tree
// draw calls, in case we have modified state in between.
gr_context_->resetContext();
AdvanceFrame();
// Get a SkCanvas that outputs to our hardware render target.
SkCanvas* canvas = GetCanvasFromRenderTarget(render_target);
canvas->save();
if (options.flags & Rasterizer::kSubmitFlags_Clear) {
canvas->clear(SkColorSetARGB(0, 0, 0, 0));
} else if (options.dirty) {
// Only a portion of the display is dirty. Reuse the previous frame
// if possible.
if (render_target_egl->ContentWasPreservedAfterSwap()) {
canvas->clipRect(CobaltRectFToSkiaRect(*options.dirty));
}
}
// Rasterize the passed in render tree to our hardware render target.
RasterizeRenderTreeToCanvas(render_tree, canvas, kBottomLeft_GrSurfaceOrigin);
{
TRACE_EVENT0("cobalt::renderer", "Skia Flush");
canvas->flush();
}
graphics_context_->SwapBuffers(render_target_egl);
canvas->restore();
}
The Skia flush() call is the function in which all of the OpenGL functions will be called (prior to that function being called, all of the drawing functions are simply serialized and queued in an internal Skia format).
Therefore, I would investigate your GL driver implementation in this case. It could be that your CPU is waiting on your GPU to consume some of the draw commands sent to it by GLES.
I wrote a command line c tool generating an sine wave and playing it using CoreAudio on the default audio output. I am initializing a
AURenderCallbackStruct and initialize an AudioUnit using AudioUnitInitialize (as already discussed in this forum). All this is working as intended, but when it comes to closing the program I am not able to close the AudioUnit, neither with using AudioOutputUnitStop(player.outputUnit); nor AudioOutputUnitStop(player.outputUnit); nor
AudioComponentInstanceDispose(player.outputUnit);
The order of appearance of these calls in the code does not change the behavior.
The program is compiled without error messages, but the sine is still audible as long as the rest of the program is running.
Here is the code I'm using for initializing the AudioUnit:
void CreateAndConnectOutputUnit (ToneGenerator *player) {
AudioComponentDescription outputcd = {0};
outputcd.componentType = kAudioUnitType_Output;
outputcd.componentSubType = kAudioUnitSubType_DefaultOutput;
outputcd.componentManufacturer = kAudioUnitManufacturer_Apple;
AudioComponent comp = AudioComponentFindNext (NULL, &outputcd);
if (comp == NULL) {
printf ("can't get output unit");
exit (-1);
}
AudioComponentInstanceNew(comp, &player->outputUnit);
// register render callback
AURenderCallbackStruct input;
input.inputProc = SineWaveRenderCallback;
input.inputProcRefCon = player;
AudioUnitSetProperty(player->outputUnit,
kAudioUnitProperty_SetRenderCallback,
kAudioUnitScope_Output,
0,
&input,
sizeof(input);
// initialize unit
AudioUnitInitialize(player->outputUnit);
}
In my main program I'm starting the AudioUnit and the sine wave.
void main {
// code for doing various things
ToneGenerator player = {0}; // create a sound object
CreateAndConnectOutputUnit (&player);
AudioOutputUnitStart(player.outputUnit);
// waiting to listen to the sine wave
sleep(3);
// attempt to stop the sound output
AudioComponentInstanceDispose(player.outputUnit);
AudioUnitUninitialize(player.outputUnit);
AudioOutputUnitStop(player.outputUnit);
//additional code that should be executed without sine wave being audible
}
As I'm new to both, this forum as well as programming in Xcode I hope that I could explain this issue in a way that you can help me out and I hope that I didn't miss the answer somewhere in the forum while searching for a solution.
Thank you in advance for your time and input,
Stefan
You should manage and unmanage your audio unit in a logical order. It doesn't make sense to stop playback on an already uninitialized audio unit, which had in fact previously been disposed of in the middle of the playback. Rather than that, try the following order:
AudioOutputUnitStop(player.outputUnit); //first stops playback
AudioUnitUninitialize(player.outputUnit); //then deallocates unit's resources
AudioComponentInstanceDispose(player.outputUnit); //finally disposes of the AU itself
The sine wave command line app you're after is a well elaborated lesson in this textbook. Please read it step by step.
Last, but not least, your question has nothing to do with C++, CoreAudio is a plain-C API, so C++ in both your title and tag are wrong and misleading.
An Audio Unit runs in an asynchronous thread that may not actually stop immediately when you call AudioOutputUnitStop. Thus, it may work better to wait a fraction of a second (at least a couple audio callback buffer durations in time) before calling AudioUnitUninitialize and AudioComponentInstanceDispose on a potentially still running audio unit.
Also, check to make sure your player.outputUnit value is a valid unit (and not an uninitialized or trashed variable) at the time you stop the unit.
I am working on migrating the drawing code of an application from GDI/GDI+ to Direct2D. So far things have been going well - however, while testing the new code, I have noticed some bizarre performance. The flow of execution I have been investigating is as follows (I have done my best to remove irrelevant code):
Create D2D Factory (on creation of app)
HRESULT hr = S_OK;
hr = D2D1CreateFactory(D2D1_FACTORY_TYPE_MULTI_THREADED, &m_pD2DFactory);
if (hr == S_FALSE) {
ASSERT(FALSE);
throw Exception(CExtString(_T("Failed to create Direct2D factory")));
}
OnDraw Callback
HWND hwnd = GetSafeHwnd();
RECT rc;
GetClientRect(&rc);
D2D1_SIZE_U size = D2D1::SizeU(rc.right - rc.left, rc.bottom - rc.top);
// Create a render target if it has been destroyed
if (!m_pRT) {
D2D1_RENDER_TARGET_PROPERTIES props = D2D1::RenderTargetProperties(
D2D1_RENDER_TARGET_TYPE_DEFAULT,
D2D1::PixelFormat(
DXGI_FORMAT_B8G8R8A8_UNORM,
D2D1_ALPHA_MODE_IGNORE),
0,
0,
D2D1_RENDER_TARGET_USAGE_NONE,
D2D1_FEATURE_LEVEL_DEFAULT);
GetD2DFactory()->CreateHwndRenderTarget(props,
D2D1::HwndRenderTargetProperties(hwnd, size),
&m_pRT);
}
m_pRT->Resize(size);
m_pRT->BeginDraw();
// Begin drawing the layers, given the
// transformation matrix and some geometric information
Draw(m_pRT, matrixD2D, rectClipWorld, rectClipDP);
HRESULT hr = m_pRT->EndDraw();
if (hr == D2DERR_RECREATE_TARGET) {
SafeRelease(m_pRT);
}
The contents of the Draw method
The draw method does a lot of fluff that is largely irrelevant to this test (as I have turned all extraneous layers off), but it eventually draws a layer that executes this method several thousand times:
void DrawStringWithEffects(ID2D1RenderTarget* m_pRT, const CString& text, const D2D1_POINT_2F& point, const COLORREF rgbFore, const COLORREF rgbBack, IDWriteTextFormat* pfont) {
// The text will be vertically centered around point.y, with point.x on the left hand side
// Create a TextLayout for the string
IDWriteTextLayout* textLayout = NULL;
GetDWriteFactory()->CreateTextLayout(text,
text.GetLength(),
pfont,
std::numeric_limits<float>::infinity(),
std::numeric_limits<float>::infinity(),
&textLayout);
DWRITE_TEXT_METRICS metrics = {0};
textLayout->GetMetrics(&metrics);
D2D1_RECT_F rect = D2D1::RectF(point.x, point.y - metrics.height/2, point.x + metrics.width, point.y + metrics.height/2);
D2D1_POINT_2F pointDraw = point;
pointDraw.y -= metrics.height/2;
ID2D1SolidColorBrush* brush = NULL;
m_pRT->CreateSolidColorBrush(ColorD2DFromCOLORREF(rgbBack), &brush);
m_pRT->FillRectangle(rect, brush);
// ^^ this is sometimes very slow!
brush->SetColor(ColorD2DFromCOLORREF(rgbFore));
m_pRT->DrawTextLayout(pointDraw, textLayout, brush, D2D1_DRAW_TEXT_OPTIONS_NONE);
// ^^ this is also sometimes very slow!
SafeRelease(&brush);
SafeRelease(&textLayout);
The vast majority of the time, the Direct2D calls are executing ~3-4 times faster than the GDI+ equivalents, which is great (generally 0.1ms compared to ~0.35ms). For some reason, though, the function calls will occasionally stall for a long period of time - upwards of 200ms combined. The offending calls are straight from the Direct2D API - FillRectangle and DrawTextLayout. Strangely, these stalls appear in the same location every time I run the application - the 73rd occurrence of the loop, then the 218th, then the 290th and so on (there is somewhat of a pattern in the differences, alternating between every ~73rd and every ~145th cycle). This is independent of the data that it draws (when I told it to skip drawing the 73rd cycle, the next cycle simply becomes the 73rd and thus stalls).
I thought this may be a GPU/CPU communication issue, so I set the render target (I am using an HWnd target) to software mode (D2D1_RENDER_TARGET_TYPE_SOFTWARE), and the results were even more strange. The stall times dropped from ~200ms to ~20ms (still not great, but hey), but there were two instances that stalled for over 2500ms! (These two, like the rest of the stalls, are completely reproducible in terms of being the n'th API call).
This is rather frustrating, as 99% of the loop is several times faster than the old implementation, but the (less than) 1% remaining hang for an abnormally long time.
To any Direct2D experts out there - what type of problem might this stalling be a symptom of? What, in general, could be causing this disconnect between my code and what D2D is doing in the background?
Direct2D buffers drawing commands (presumably to optimize them). You can't look at the performance of an individual drawing command, you must look at the total time between BeginDraw() and EndDraw(). If you want to force each drawing command to execute immediately, you must follow each one with a call to Flush(). That's probably a bad idea for performance though.
https://msdn.microsoft.com/en-us/library/windows/desktop/dd371768(v=vs.85).aspx
After BeginDraw is called, a render target will normally build up a
batch of rendering commands, but defer processing of these commands
until either an internal buffer is full, the Flush method is called,
or until EndDraw is called.
I'm currently working on a Cocoa application that works with PDFs, and am using Apple's PDFKit to do the work. Saving the PDF is proving a problem, as I'd like to show a progress bar while that's happening, which doesn't seem to be possible using the standard writeToURL: method. So, I went and used Grand Central Dispatch instead.
The problem with this is that the dataRepresentation method used to get the NSData to write is terribly slow in converting any PDF larger than ~3MB to NSData, and so the progress bar stalls for a few seconds while my program is waiting for the data, which seems to make the users think the program has stalled completely. And I don't really want them thinking that.
My question is, is there anything I can do to either speed up the dataRepresentation method, or report its progress to the user?
Here's the Grand Central Dispatch code I ended up writing:
NSData *pdf = [doc dataRepresentation]; // R-e-a-l-l-y S-l-o-w
dispatch_queue_t queue = dispatch_get_current_queue();
dispatch_data_t dat = dispatch_data_create([pdf bytes], [pdf length], queue, DISPATCH_DATA_DESTRUCTOR_DEFAULT);
__block dispatch_io_t channel =
dispatch_io_create_with_path(DISPATCH_IO_STREAM,
[path UTF8String], // Convert to C-string
O_WRONLY, // Open for writing
0, // No extra flags
queue,
^(int error){
// Cleanup code for normal channel operation.
// Assumes that dispatch_io_close was called elsewhere.
if (error == 0) {
dispatch_release(channel);
channel = NULL;
}
});
// The next two lines make sure that the block in dispatch_io_write
// gets called about 60 times, so that it can update the progress bar.
dispatch_io_set_low_water(channel,[pdf length]/60);
dispatch_io_set_high_water(channel,[pdf length]/60);
dispatch_io_write(channel,
0,
dat,
queue,
^(bool done, dispatch_data_t data, int error) {
if (data) {
// Increment progress bar
}
if (error) {
// Handle errors
}
if (done) {
dispatch_io_close(channel, NULL);
}
});
dispatch_release(dat);
dispatch_release(queue);
Use the PDFDocumentDidBeginPageWriteNotification and PDFDocumentDidEndPageWriteNotification notifications, which are sent during -writeToURL:. The notifications tell you what page is processing, which you can compare to the total number of pages in the document to show progress.
I have a determinate progress indicator. It is working just like I would expect it to but it does not disappear after it reaches maxValue. I have set the progress indicator to not display when stopped in the main.nib file, I have also entered it into the awakeFromNib{} method.
I put a log at the end of the routine to make sure the [displayWhenStopped] setting was still set to NO and it is.
Here is my code :
-(void)getEvents:(NSURL *)mffFile{
NSMutableArray * eventTypeResults =[[NSMutableArray alloc]init];
EWaveformRecording *ptrToRcdFile = [EWaveformRecording openRecording:mffFile permission:readOnly user:nil convertFileFormat:NO openReadOnlyAnyway:NO];
NSArray *events = [ptrToRcdFile getEvents];
//get the size of events for the progressbar and instantiate a loop counter
NSInteger total = [events count];
int loop = 0;
//set progress bar params
[self->meter_ setUsesThreadedAnimation:YES];
[self->meter_ setControlSize:NSMiniControlSize];
[self->meter_ setMaxValue:(double)total];
for(EEvent* event in events){
loop ++;
if(![eventTypeResults containsObject:event.code]){
NSLog(#"check eventNames in getEvents %#", event.code);
[eventTypeResults addObject: event.code];
}//end if
//display loop increment in progress bar
[self->meter_ setDoubleValue:(1000*(double)loop)/1000];
}//end for
//send the eventTypesResults array to the EventExport class
[evtPtr setEventsAvailableList:eventTypeResults];
}
What I have tried:
with and without [setUsesThreadedAnimation] which I don't totally understand; it does slow down the progress bar which makes it look better but the docs say only indeterminate types should be effected by animation.
I have tried using [start & stop animation]
I have tried [setDisplayWhenStopped:NO] after my loop
Any help is greatly appreciated
MIke
This is what I learned.
I should not be allowing the progress bar to run on a different thread even though it looks like its working because the NSProgressIndicator can no longer respond to the settings in the main thread, so the proper thing to do is to not instantiate that method, however , that was not the solution to my problem; I was doing everything else right, but the main thread could not redraw the progress because it's busy with all the other calls in the UI. The solution was to implement NSRunLoop so that each iteration of the loop interrupts the main thread and redraws the progress meter , then returns control.