int net_resolve(const char *hostname, net_addr_t *addr, const char **err) { int rval = -1; PP_Resource res = ppb_hostresolver->Create(g_Instance); struct PP_HostResolver_Hint hint = {PP_NETADDRESS_FAMILY_UNSPECIFIED, 0}; int r = ppb_hostresolver->Resolve(res, hostname, 0, &hint, PP_BlockUntilComplete()); if(r == 0) { // OK if(pepper_Resolver_to_net_addr(addr, res)) { *err = "Invalid address"; } else { rval = 0; } } else { *err = pepper_errmsg(r); } ppb_core->ReleaseResource(res); return rval; }
void Render() { struct PP_Size* psize = &g_Context.size; PP_ImageDataFormat format = PP_IMAGEDATAFORMAT_BGRA_PREMUL; PP_Resource image = g_pImageData->Create(PSGetInstanceId(), format, psize, PP_FALSE); uint8_t* pixels = g_pImageData->Map(image); struct PP_ImageDataDesc desc; uint8_t* cell_temp; uint32_t x, y; if (!g_Context.cell_in || !g_Context.cell_out) return; g_pImageData->Describe(image, &desc); Stir(desc.size.width, desc.size.height); for (y = 1; y < desc.size.height - 1; ++y) { uint8_t *src0 = (g_Context.cell_in + (y - 1) * desc.size.width) + 1; uint8_t *src1 = src0 + desc.size.width; uint8_t *src2 = src1 + desc.size.width; int count; uint32_t color; uint8_t *dst = (g_Context.cell_out + y * desc.size.width) + 1; uint32_t *pixel_line = (uint32_t*) (pixels + y * desc.stride); for (x = 1; x < (desc.size.width - 1); ++x) { count = src0[-1] + src0[0] + src0[1] + src1[-1] + src1[0] * 9 + src1[1] + src2[-1] + src2[0] + src2[1]; color = kNeighborColors[count]; *pixel_line++ = color; *dst++ = kIsAlive[count]; ++src0; ++src1; ++src2; } } cell_temp = g_Context.cell_in; g_Context.cell_in = g_Context.cell_out; g_Context.cell_out = cell_temp; g_pImageData->Unmap(image); g_pGraphics2D->ReplaceContents(g_Context.ctx, image); g_pGraphics2D->Flush(g_Context.ctx, PP_BlockUntilComplete()); g_pCore->ReleaseResource(image); }
void screen_size_changed_2d(int32_t width, int32_t height) { if (!graphics_initialized || (screenSize.width == width && screenSize.height == height) || width < canvasSize.width || height < canvasSize.height) { return; } screenSize.width = width; screenSize.height = height; /* Unbind and release old graphics context. */ if (!ppb_instance_interface->BindGraphics(pp_instance, 0)) { write_log("Failed to unbind old context from instance.\n"); return; } ppb_core_interface->ReleaseResource(graphics_context); /* Create new graphics context. */ graphics_context = ppb_g2d_interface->Create( pp_instance, &screenSize, PP_TRUE /* is_always_opaque */); if (!graphics_context) { write_log("Could not obtain a PPB_Graphics2D context.\n"); return; } if (!ppb_instance_interface->BindGraphics(pp_instance, graphics_context)) { write_log("Failed to bind context to instance.\n"); return; } /* Give the screen around the emulator a dark gray background. */ PP_Resource temp_image_data = ppb_image_data_interface->Create(pp_instance, preferredFormat, &screenSize, /* init_to_zero */ PP_FALSE); if (!temp_image_data) { write_log("Could not create image data.\n"); return; } uint32_t* pixels = ppb_image_data_interface->Map(temp_image_data); uint32_t* end = pixels + screenSize.width * screenSize.height; for (uint32_t* p = pixels; p < end; ++p) { /* This assumes each color channel is 8-bits */ *p = alpha_mask | 0x33333333 /* dark grey background */; } ppb_image_data_interface->Unmap(temp_image_data); ppb_g2d_interface->ReplaceContents(graphics_context, temp_image_data); ppb_g2d_interface->Flush(graphics_context, PP_BlockUntilComplete()); ppb_core_interface->ReleaseResource(temp_image_data); /* Set the top corner for the canvas on the new screen. */ top.x = (screenSize.width - canvasSize.width) / 2; top.y = (screenSize.height - canvasSize.height) / 2; }
static int tcp_write(tcpcon_t *tc, const void *data, size_t len) { while(len > 0) { int r = ppb_tcpsocket->Write(tc->fd, data, len, PP_BlockUntilComplete()); if(r <= 0) return -1; len -= r; data += r; } return 0; }
tcpcon_t * tcp_connect_arch(const net_addr_t *na, char *errbuf, size_t errlen, int timeout, cancellable_t *c, int dbg) { PP_Resource sock = ppb_tcpsocket->Create(g_Instance); PP_Resource addr; struct PP_NetAddress_IPv4 ipv4_addr = {}; struct PP_NetAddress_IPv6 ipv6_addr = {}; switch(na->na_family) { case 4: memcpy(ipv4_addr.addr, na->na_addr, 4); wr16_be((uint8_t *)&ipv4_addr.port, na->na_port); addr = ppb_netaddress->CreateFromIPv4Address(g_Instance, &ipv4_addr); break; case 6: memcpy(ipv6_addr.addr, na->na_addr, 16); wr16_be((uint8_t *)&ipv6_addr.port, na->na_port); addr = ppb_netaddress->CreateFromIPv6Address(g_Instance, &ipv6_addr); break; default: abort(); } if(dbg) { // debug struct PP_Var remote = ppb_netaddress->DescribeAsString(addr, 1); uint32_t len; const char *s = ppb_var->VarToUtf8(remote, &len); TRACE(TRACE_DEBUG, "TCP", "Connecting to %d %.*s", len, len, s); ppb_var->Release(remote); } int r = ppb_tcpsocket->Connect(sock, addr, PP_BlockUntilComplete()); ppb_core->ReleaseResource(addr); if(r) { snprintf(errbuf, errlen, "Unable to connect -- %s", pepper_errmsg(r)); ppb_core->ReleaseResource(sock); return NULL; } tcpcon_t *tc = calloc(1, sizeof(tcpcon_t)); tc->fd = sock; htsbuf_queue_init(&tc->spill, 0); tc->read = tcp_read; tc->write = tcp_write; return tc; }
static int tcp_read(tcpcon_t *tc, void *buf, size_t len, int all, net_read_cb_t *cb, void *opaque) { int c, tot = 0; if(!all) { c = ppb_tcpsocket->Read(tc->fd, buf, len, PP_BlockUntilComplete()); return c > 0 ? c : -1; } while(tot != len) { c = ppb_tcpsocket->Read(tc->fd, buf + tot, len - tot, PP_BlockUntilComplete()); if(c < 1) return -1; tot += c; if(cb != NULL) cb(opaque, tot); } return tot; }
STATIC_INLINE void pepper_graphics2d_flush_screen( struct vidbuf_description *gfxinfo, int32_t first_line, int32_t last_line) { /* We can't use Graphics2D->ReplaceContents here because the emulator * only draws partial updates in the buffer and expects the remaining lines * to be unchanged from the previous frame. ReplaceContents would thus * require a memcpy of the complete canvas for every frame, as the * buffer given by Chrome when using ReplaceContents followed by * Create and Map will generally not contain the previous frame, * but the one before that (or garbage). */ ppb_g2d_interface->PaintImageData(graphics_context, image_data, &top, &src_rect); ppb_g2d_interface->Flush(graphics_context, PP_BlockUntilComplete()); /* TODO(cstefansen): Properly throttle 2D graphics to 50 Hz in PAL mode. */ }
STATIC_INLINE void pepper_graphics3d_flush_screen( struct vidbuf_description *gfxinfo, int32_t first_line, int32_t last_line) { glTexSubImage2D (GL_TEXTURE_2D, 0 /* level */, 0, 0, gfxvidinfo.width, gfxvidinfo.height, GL_RGB, pixel_data_type, gfxinfo->bufmem); glDrawArrays(GL_TRIANGLE_STRIP, 0, 4); ppb_g3d_interface->SwapBuffers(graphics_context, PP_BlockUntilComplete()); /* TODO(cstefansen): Properly throttle 3D graphics to 50 Hz in PAL mode. */ /* Currently, the frame rate is throttled by finish_sound_buffer * in sd-pepper/sound.c, but this is less than ideal, as it only * provides throttling when sound is playing. It does, however, * mean that scrolling is noticably smoother when no music is * playing because the emulator can go to 60 Hz. */ }
void Render() { struct PP_Size* psize = &g_Context.size; PP_ImageDataFormat format = PP_IMAGEDATAFORMAT_BGRA_PREMUL; /* * Create a buffer to draw into. Since we are waiting until the next flush * chrome has an opportunity to cache this buffer see ppb_graphics_2d.h. */ PP_Resource image = g_pImageData->Create(PSGetInstanceId(), format, psize, PP_FALSE); uint8_t* pixels = g_pImageData->Map(image); struct PP_ImageDataDesc desc; uint8_t* cell_temp; uint32_t x, y; /* If we somehow have not allocated these pointers yet, skip this frame. */ if (!g_Context.cell_in || !g_Context.cell_out) return; /* Get the stride. */ g_pImageData->Describe(image, &desc); /* Stir up the edges to prevent the simulation from reaching steady state. */ Stir(desc.size.width, desc.size.height); /* Do neighbor summation; apply rules, output pixel color. */ for (y = 1; y < desc.size.height - 1; ++y) { uint8_t *src0 = (g_Context.cell_in + (y - 1) * desc.size.width) + 1; uint8_t *src1 = src0 + desc.size.width; uint8_t *src2 = src1 + desc.size.width; int count; uint32_t color; uint8_t *dst = (g_Context.cell_out + y * desc.size.width) + 1; uint32_t *pixel_line = (uint32_t*) (pixels + y * desc.stride); for (x = 1; x < (desc.size.width - 1); ++x) { /* Jitter and sum neighbors. */ count = src0[-1] + src0[0] + src0[1] + src1[-1] + + src1[1] + src2[-1] + src2[0] + src2[1]; /* Include center cell. */ count = count + count + src1[0]; /* Use table lookup indexed by count to determine pixel & alive state. */ color = kNeighborColors[count]; *pixel_line++ = color; *dst++ = kIsAlive[count]; ++src0; ++src1; ++src2; } } cell_temp = g_Context.cell_in; g_Context.cell_in = g_Context.cell_out; g_Context.cell_out = cell_temp; /* Unmap the range, we no longer need it. */ g_pImageData->Unmap(image); /* Replace the contexts, and block until it's on the screen. */ g_pGraphics2D->ReplaceContents(g_Context.ctx, image); g_pGraphics2D->Flush(g_Context.ctx, PP_BlockUntilComplete()); /* Release the image data, we no longer need it. */ g_pCore->ReleaseResource(image); }
int32_t graphics_3d_subinit(uint32_t *Rmask, uint32_t *Gmask, uint32_t *Bmask, uint32_t *Amask) { /* Pepper Graphics3D setup. */ PPB_Instance *ppb_instance_interface = (PPB_Instance *) NaCl_GetInterface(PPB_INSTANCE_INTERFACE); if (!ppb_instance_interface) { write_log("Could not acquire PPB_Instance interface.\n"); return 0; } ppb_g3d_interface = (PPB_Graphics3D *) NaCl_GetInterface(PPB_GRAPHICS_3D_INTERFACE); if (!ppb_g3d_interface) { write_log("Could not acquire PPB_Graphics3D interface.\n"); return 0; } pp_instance = NaCl_GetInstance(); if (!pp_instance) { write_log("Could not find current Pepper instance.\n"); return 0; } int32_t attribs[] = { PP_GRAPHICS3DATTRIB_ALPHA_SIZE, 8, PP_GRAPHICS3DATTRIB_DEPTH_SIZE, 24, PP_GRAPHICS3DATTRIB_STENCIL_SIZE, 8, PP_GRAPHICS3DATTRIB_SAMPLES, 0, PP_GRAPHICS3DATTRIB_SAMPLE_BUFFERS, 0, PP_GRAPHICS3DATTRIB_WIDTH, gfxvidinfo.width, PP_GRAPHICS3DATTRIB_HEIGHT, gfxvidinfo.height, PP_GRAPHICS3DATTRIB_GPU_PREFERENCE, PP_GRAPHICS3DATTRIB_GPU_PREFERENCE_PERFORMANCE, PP_GRAPHICS3DATTRIB_NONE }; graphics_context = ppb_g3d_interface->Create( pp_instance, 0 /* share_context */, attribs); if (!graphics_context) { write_log("Could not obtain a PPB_Graphics3D context.\n"); return 0; } if (!ppb_instance_interface->BindGraphics(pp_instance, graphics_context)) { write_log("Failed to bind context to instance.\n"); return 0; } glSetCurrentContextPPAPI(graphics_context); /* UAE gfxvidinfo setup. */ /* TODO(cstefansen): Implement gfx double-buffering if perf. mandates it. */ gfxvidinfo.pixbytes = 2; /* 16-bit graphics */ gfxvidinfo.rowbytes = gfxvidinfo.width * gfxvidinfo.pixbytes; gfxvidinfo.bufmem = (uint8_t *) calloc(round_up_to_power_of_2(gfxvidinfo.rowbytes), round_up_to_power_of_2(gfxvidinfo.height)); gfxvidinfo.flush_screen = pepper_graphics3d_flush_screen; *Rmask = 0x0000F800, *Gmask = 0x000007E0, *Bmask = 0x0000001F, *Amask = 0; /* OpenGL ES setup. */ glViewport(0, 0, gfxvidinfo.width, gfxvidinfo.height); glClearColor(0.0f, 0.0f, 0.0f, 1.0f); glDisable(GL_DEPTH_TEST); /* Uniform index. */ enum { UNIFORM_VIDEOFRAME, UNIFORM_INPUTCOLOR, UNIFORM_THRESHOLD, NUM_UNIFORMS }; GLint uniforms[NUM_UNIFORMS]; /* Attribute index. */ enum { ATTRIB_VERTEX, ATTRIB_TEXTUREPOSITON, NUM_ATTRIBUTES }; static GLuint g_programObj; static GLuint g_textureID; char *g_VShaderData = "attribute vec4 position;" "attribute vec4 inputTextureCoordinate;" "varying vec2 textureCoordinate;" "void main()" "{" "gl_Position = position;" "textureCoordinate = inputTextureCoordinate.xy;" "}"; char *g_FShaderData = "varying highp vec2 textureCoordinate;" "uniform sampler2D videoFrame;" "void main()" "{" "gl_FragColor = texture2D(videoFrame, textureCoordinate);" "}"; GLuint g_vertexShader; GLuint g_fragmentShader; g_vertexShader = compileShader(GL_VERTEX_SHADER, g_VShaderData); g_fragmentShader = compileShader(GL_FRAGMENT_SHADER, g_FShaderData); g_programObj = glCreateProgram(); glAttachShader(g_programObj, g_vertexShader); glAttachShader(g_programObj, g_fragmentShader); glBindAttribLocation(g_programObj, ATTRIB_VERTEX, "position"); glBindAttribLocation(g_programObj, ATTRIB_TEXTUREPOSITON, "inputTextureCoordinate"); glLinkProgram(g_programObj); uniforms[UNIFORM_VIDEOFRAME] = glGetUniformLocation(g_programObj, "videoFrame"); uniforms[UNIFORM_INPUTCOLOR] = glGetUniformLocation(g_programObj, "inputColor"); uniforms[UNIFORM_THRESHOLD] = glGetUniformLocation(g_programObj, "threshold"); glGenTextures(1, &g_textureID); glActiveTexture(GL_TEXTURE0); glBindTexture(GL_TEXTURE_2D, g_textureID); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); GLint textureWidth = round_up_to_power_of_2(gfxvidinfo.width); GLint textureHeight = round_up_to_power_of_2(gfxvidinfo.height); glTexImage2D(GL_TEXTURE_2D, 0 /* level */, GL_RGB, textureWidth, textureHeight, 0, GL_RGB, pixel_data_type, gfxvidinfo.bufmem); static const GLfloat squareVertices[] = { -1.0f, -1.0, 1.0f, -1.0, -1.0f, 1.0, 1.0f, 1.0, }; GLfloat xFraction = ((GLfloat) gfxvidinfo.width) / (GLfloat) textureWidth; GLfloat yFraction = ((GLfloat) gfxvidinfo.height) / (GLfloat) textureHeight; static GLfloat textureVertices[] = { 0.0f, 0.0f /* yFraction */, 0.0f /* xFraction */, 0.0f /* yFraction */, 0.0f, 0.0f, 0.0f /* xFraction */, 0.0f, }; textureVertices[1] = yFraction; textureVertices[2] = xFraction; textureVertices[3] = yFraction; textureVertices[6] = xFraction; glUseProgram(g_programObj); glUniform1i(uniforms[UNIFORM_VIDEOFRAME], 0); glVertexAttribPointer(ATTRIB_VERTEX, 2, GL_FLOAT, 0, 0, squareVertices); glEnableVertexAttribArray(ATTRIB_VERTEX); glVertexAttribPointer(ATTRIB_TEXTUREPOSITON, 2, GL_FLOAT, 0, 0, textureVertices); glEnableVertexAttribArray(ATTRIB_TEXTUREPOSITON); DEBUG_LOG("Shaders compiled and program linked.\n"); GLenum glErrorStatus = glGetError(); if (glErrorStatus) { write_log("GL error %d while initializing.\n", glErrorStatus); return 0; } glDrawArrays(GL_TRIANGLE_STRIP, 0, 4); ppb_g3d_interface->SwapBuffers(graphics_context, PP_BlockUntilComplete()); gettimeofday(&tv_prev, NULL); return 1; /* Success! */ }