static int _cg_rect_slices_for_size(int size_to_fill, int max_span_size, int max_waste, c_array_t *out_spans) { int n_spans = 0; cg_span_t span; /* Init first slice span */ span.start = 0; span.size = max_span_size; span.waste = 0; /* Repeat until whole area covered */ while (size_to_fill >= span.size) { /* Add another slice span of same size */ if (out_spans) c_array_append_val(out_spans, span); span.start += span.size; size_to_fill -= span.size; n_spans++; } /* Add one last smaller slice span */ if (size_to_fill > 0) { span.size = size_to_fill; if (out_spans) c_array_append_val(out_spans, span); n_spans++; } return n_spans; }
static int _cg_pot_slices_for_size(int size_to_fill, int max_span_size, int max_waste, c_array_t *out_spans) { int n_spans = 0; cg_span_t span; /* Init first slice span */ span.start = 0; span.size = max_span_size; span.waste = 0; /* Fix invalid max_waste */ if (max_waste < 0) max_waste = 0; while (true) { /* Is the whole area covered? */ if (size_to_fill > span.size) { /* Not yet - add a span of this size */ if (out_spans) c_array_append_val(out_spans, span); span.start += span.size; size_to_fill -= span.size; n_spans++; } else if (span.size - size_to_fill <= max_waste) { /* Yes and waste is small enough */ /* Pick the next power of two up from size_to_fill. This can sometimes be less than the span.size that would be chosen otherwise */ span.size = _cg_util_next_p2(size_to_fill); span.waste = span.size - size_to_fill; if (out_spans) c_array_append_val(out_spans, span); return ++n_spans; } else { /* Yes but waste is too large */ while (span.size - size_to_fill > max_waste) { span.size /= 2; c_assert(span.size > 0); } } } /* Can't get here */ return 0; }
static void data_buffer_stream_read_idle(void *user_data) { rig_pb_stream_t *stream = user_data; int i; rut_poll_shell_remove_idle_FIXME(stream->shell, stream->buffer.read_idle); stream->buffer.read_idle = NULL; c_return_if_fail(stream->type == STREAM_TYPE_BUFFER); c_return_if_fail(stream->buffer.other_end != NULL); c_return_if_fail(stream->buffer.other_end->type == STREAM_TYPE_BUFFER); c_return_if_fail(stream->read_callback != NULL); for (i = 0; i < stream->buffer.incoming_write_closures->len; i++) { rig_pb_stream_write_closure_t *closure = c_array_index(stream->buffer.incoming_write_closures, void *, i); stream->read_callback(stream, (uint8_t *)closure->buf.base, closure->buf.len, stream->read_data); /* Give the closure back so it can be freed */ c_array_append_val(stream->buffer.other_end->buffer.finished_write_closures, closure); } c_array_set_size(stream->buffer.incoming_write_closures, 0); drain_finished_write_closures(stream); }
void rig_pb_stream_disconnect(rig_pb_stream_t *stream) { switch (stream->type) { #ifdef USE_UV case STREAM_TYPE_FD: uv_read_stop((uv_stream_t *)&stream->fd.uv_fd_pipe); uv_close((uv_handle_t *)&stream->fd.uv_fd_pipe, NULL /* closed callback */); break; case STREAM_TYPE_TCP: uv_read_stop((uv_stream_t *)&stream->tcp.socket); uv_close((uv_handle_t *)&stream->tcp.socket, NULL /* closed callback */); break; #endif case STREAM_TYPE_BUFFER: { int i; /* Give all incoming write closures back to the other end * so they can be freed */ for (i = 0; i < stream->buffer.incoming_write_closures->len; i++) { rig_pb_stream_write_closure_t *closure = c_array_index(stream->buffer.incoming_write_closures, void *, i); c_array_append_val(stream->buffer.other_end->buffer.finished_write_closures, closure); } c_array_free(stream->buffer.incoming_write_closures, true /* free storage */); stream->buffer.incoming_write_closures = NULL; drain_finished_write_closures(stream); c_array_free(stream->buffer.finished_write_closures, true /* free storage */); stream->buffer.finished_write_closures = NULL; stream->buffer.other_end->buffer.other_end = NULL; stream->buffer.other_end = NULL; } if (stream->buffer.read_idle) { rut_poll_shell_remove_idle_FIXME(stream->shell, stream->buffer.read_idle); stream->buffer.read_idle = NULL; } break; #ifdef __EMSCRIPTEN__ case STREAM_TYPE_WORKER_IPC: stream->worker_ipc.worker = 0; break; case STREAM_TYPE_WEBSOCKET_CLIENT: if (stream->websocket_client.socket != -1) { close(stream->websocket_client.socket); stream->websocket_client.socket = -1; } break; #endif #ifdef USE_UV case STREAM_TYPE_WEBSOCKET_SERVER: stream->websocket_server.ctx = NULL; break; #endif case STREAM_TYPE_DISCONNECTED: #ifdef USE_UV if (stream->resolving) uv_cancel((uv_req_t *)&stream->resolver); if (stream->connecting) uv_cancel((uv_req_t *)&stream->connection_request); #endif return; } stream->type = STREAM_TYPE_DISCONNECTED; rut_closure_list_invoke(&stream->on_error_closures, rig_pb_stream_callback_t, stream); }
void rig_pb_stream_write(rig_pb_stream_t *stream, rig_pb_stream_write_closure_t *closure) { c_return_if_fail(stream->type != STREAM_TYPE_DISCONNECTED); switch (stream->type) { case STREAM_TYPE_BUFFER: { c_return_if_fail(stream->buffer.other_end != NULL); c_return_if_fail(stream->buffer.other_end->type == STREAM_TYPE_BUFFER); c_array_append_val(stream->buffer.other_end->buffer.incoming_write_closures, closure); queue_data_buffer_stream_read(stream->buffer.other_end); break; } #ifdef USE_UV case STREAM_TYPE_FD: case STREAM_TYPE_TCP: { closure->write_req.data = closure; uv_write(&closure->write_req, (uv_stream_t *)&stream->fd.uv_fd_pipe, &closure->buf, 1, /* n buffers */ uv_write_done_cb); break; } case STREAM_TYPE_WEBSOCKET_SERVER: { struct wslay_event_fragmented_msg arg; memset(&arg, 0, sizeof(arg)); arg.opcode = WSLAY_BINARY_FRAME; arg.source.data = closure; arg.read_callback = fragmented_wslay_read_cb; closure->current_offset = 0; wslay_event_queue_fragmented_msg(stream->websocket_server.ctx, &arg); wslay_event_send(stream->websocket_server.ctx); break; } #endif #ifdef __EMSCRIPTEN__ case STREAM_TYPE_WORKER_IPC: if (stream->worker_ipc.in_worker) rig_emscripten_worker_post_to_main(closure->buf.base, closure->buf.len); else rig_emscripten_worker_post(stream->worker_ipc.worker, "rig_pb_stream_worker_onmessage", closure->buf.base, closure->buf.len); closure->done_callback(closure); break; case STREAM_TYPE_WEBSOCKET_CLIENT: c_debug("stream: websocket send() %d bytes", closure->buf.len); send(stream->websocket_client.socket, closure->buf.base, closure->buf.len, 0 /* flags */); closure->done_callback(closure); break; #endif case STREAM_TYPE_DISCONNECTED: c_warn_if_reached(); break; } }
static bool setup_spans(cg_device_t *dev, cg_texture_2d_sliced_t *tex_2ds, int width, int height, int max_waste, cg_pixel_format_t internal_format, cg_error_t **error) { int max_width; int max_height; int n_x_slices; int n_y_slices; int (*slices_for_size)(int, int, int, c_array_t *); /* Initialize size of largest slice according to supported features */ if (cg_has_feature(dev, CG_FEATURE_ID_TEXTURE_NPOT)) { max_width = width; max_height = height; slices_for_size = _cg_rect_slices_for_size; } else { max_width = _cg_util_next_p2(width); max_height = _cg_util_next_p2(height); slices_for_size = _cg_pot_slices_for_size; } /* Negative number means no slicing forced by the user */ if (max_waste <= -1) { cg_span_t span; /* Check if size supported else bail out */ if (!dev->driver_vtable->texture_2d_can_create(dev, max_width, max_height, internal_format)) { _cg_set_error(error, CG_TEXTURE_ERROR, CG_TEXTURE_ERROR_SIZE, "Sliced texture size of %d x %d not possible " "with max waste set to -1", width, height); return false; } n_x_slices = 1; n_y_slices = 1; /* Init span arrays */ tex_2ds->slice_x_spans = c_array_sized_new(false, false, sizeof(cg_span_t), 1); tex_2ds->slice_y_spans = c_array_sized_new(false, false, sizeof(cg_span_t), 1); /* Add a single span for width and height */ span.start = 0; span.size = max_width; span.waste = max_width - width; c_array_append_val(tex_2ds->slice_x_spans, span); span.size = max_height; span.waste = max_height - height; c_array_append_val(tex_2ds->slice_y_spans, span); } else { /* Decrease the size of largest slice until supported by GL */ while (!dev->driver_vtable->texture_2d_can_create(dev, max_width, max_height, internal_format)) { /* Alternate between width and height */ if (max_width > max_height) max_width /= 2; else max_height /= 2; if (max_width == 0 || max_height == 0) { /* Maybe it would be ok to just c_warn_if_reached() for this * codepath */ _cg_set_error(error, CG_TEXTURE_ERROR, CG_TEXTURE_ERROR_SIZE, "No suitable slice geometry found"); free_spans(tex_2ds); return false; } } /* Determine the slices required to cover the bitmap area */ n_x_slices = slices_for_size(width, max_width, max_waste, NULL); n_y_slices = slices_for_size(height, max_height, max_waste, NULL); /* Init span arrays with reserved size */ tex_2ds->slice_x_spans = c_array_sized_new(false, false, sizeof(cg_span_t), n_x_slices); tex_2ds->slice_y_spans = c_array_sized_new(false, false, sizeof(cg_span_t), n_y_slices); /* Fill span arrays with info */ slices_for_size(width, max_width, max_waste, tex_2ds->slice_x_spans); slices_for_size(height, max_height, max_waste, tex_2ds->slice_y_spans); } return true; }