1f54e72962991005a3c0cc7dce0c550a14af90792Chris Lattner// Copyright (c) 2013 The Chromium Authors. All rights reserved. 2f54e72962991005a3c0cc7dce0c550a14af90792Chris Lattner// Use of this source code is governed by a BSD-style license that can be 3f54e72962991005a3c0cc7dce0c550a14af90792Chris Lattner// found in the LICENSE file. 4f54e72962991005a3c0cc7dce0c550a14af90792Chris Lattner 5f54e72962991005a3c0cc7dce0c550a14af90792Chris Lattner#include "content/common/gpu/stream_texture_android.h" 6f54e72962991005a3c0cc7dce0c550a14af90792Chris Lattner 7f54e72962991005a3c0cc7dce0c550a14af90792Chris Lattner#include "base/bind.h" 8f54e72962991005a3c0cc7dce0c550a14af90792Chris Lattner#include "content/common/android/surface_texture_peer.h" 9f54e72962991005a3c0cc7dce0c550a14af90792Chris Lattner#include "content/common/gpu/gpu_channel.h" 10f54e72962991005a3c0cc7dce0c550a14af90792Chris Lattner#include "content/common/gpu/gpu_messages.h" 11f54e72962991005a3c0cc7dce0c550a14af90792Chris Lattner#include "gpu/command_buffer/service/context_group.h" 12f54e72962991005a3c0cc7dce0c550a14af90792Chris Lattner#include "gpu/command_buffer/service/context_state.h" 13f54e72962991005a3c0cc7dce0c550a14af90792Chris Lattner#include "gpu/command_buffer/service/gles2_cmd_decoder.h" 14f54e72962991005a3c0cc7dce0c550a14af90792Chris Lattner#include "gpu/command_buffer/service/texture_manager.h" 15cd6636c737a82949ad13db2d0d918af6424fb78bDuncan Sands#include "ui/gfx/size.h" 16f54e72962991005a3c0cc7dce0c550a14af90792Chris Lattner#include "ui/gl/scoped_make_current.h" 17f54e72962991005a3c0cc7dce0c550a14af90792Chris Lattner 18f54e72962991005a3c0cc7dce0c550a14af90792Chris Lattnernamespace content { 19f54e72962991005a3c0cc7dce0c550a14af90792Chris Lattner 20f54e72962991005a3c0cc7dce0c550a14af90792Chris Lattnerusing gpu::gles2::ContextGroup; 21f54e72962991005a3c0cc7dce0c550a14af90792Chris Lattnerusing gpu::gles2::GLES2Decoder; 22f54e72962991005a3c0cc7dce0c550a14af90792Chris Lattnerusing gpu::gles2::TextureManager; 23f54e72962991005a3c0cc7dce0c550a14af90792Chris Lattnerusing gpu::gles2::TextureRef; 24f54e72962991005a3c0cc7dce0c550a14af90792Chris Lattner 25f54e72962991005a3c0cc7dce0c550a14af90792Chris Lattner// static 26f54e72962991005a3c0cc7dce0c550a14af90792Chris Lattnerbool StreamTexture::Create( 27f54e72962991005a3c0cc7dce0c550a14af90792Chris Lattner GpuCommandBufferStub* owner_stub, 28f54e72962991005a3c0cc7dce0c550a14af90792Chris Lattner uint32 client_texture_id, 29f54e72962991005a3c0cc7dce0c550a14af90792Chris Lattner int stream_id) { 30f54e72962991005a3c0cc7dce0c550a14af90792Chris Lattner GLES2Decoder* decoder = owner_stub->decoder(); 31db125cfaf57cc83e7dd7453de2d509bc8efd0e5eChris Lattner TextureManager* texture_manager = 32db125cfaf57cc83e7dd7453de2d509bc8efd0e5eChris Lattner decoder->GetContextGroup()->texture_manager(); 33f54e72962991005a3c0cc7dce0c550a14af90792Chris Lattner TextureRef* texture = texture_manager->GetTexture(client_texture_id); 34c8cb8ef9c2d5e354db661022d707a19b3533c00eChris Lattner 35c8cb8ef9c2d5e354db661022d707a19b3533c00eChris Lattner if (texture && (!texture->texture()->target() || 36c8cb8ef9c2d5e354db661022d707a19b3533c00eChris Lattner texture->texture()->target() == GL_TEXTURE_EXTERNAL_OES)) { 37c8cb8ef9c2d5e354db661022d707a19b3533c00eChris Lattner 38c8cb8ef9c2d5e354db661022d707a19b3533c00eChris Lattner // TODO: Ideally a valid image id was returned to the client so that 39c8cb8ef9c2d5e354db661022d707a19b3533c00eChris Lattner // it could then call glBindTexImage2D() for doing the following. 40c8cb8ef9c2d5e354db661022d707a19b3533c00eChris Lattner scoped_refptr<gfx::GLImage> gl_image( 41c8cb8ef9c2d5e354db661022d707a19b3533c00eChris Lattner new StreamTexture(owner_stub, stream_id, texture->service_id())); 42c8cb8ef9c2d5e354db661022d707a19b3533c00eChris Lattner gfx::Size size = gl_image->GetSize(); 43f54e72962991005a3c0cc7dce0c550a14af90792Chris Lattner texture_manager->SetTarget(texture, GL_TEXTURE_EXTERNAL_OES); 44f54e72962991005a3c0cc7dce0c550a14af90792Chris Lattner texture_manager->SetLevelInfo(texture, 45f54e72962991005a3c0cc7dce0c550a14af90792Chris Lattner GL_TEXTURE_EXTERNAL_OES, 46f54e72962991005a3c0cc7dce0c550a14af90792Chris Lattner 0, 47f54e72962991005a3c0cc7dce0c550a14af90792Chris Lattner GL_RGBA, 48c8cb8ef9c2d5e354db661022d707a19b3533c00eChris Lattner size.width(), 49f54e72962991005a3c0cc7dce0c550a14af90792Chris Lattner size.height(), 50f54e72962991005a3c0cc7dce0c550a14af90792Chris Lattner 1, 51f54e72962991005a3c0cc7dce0c550a14af90792Chris Lattner 0, 52f54e72962991005a3c0cc7dce0c550a14af90792Chris Lattner GL_RGBA, 53f54e72962991005a3c0cc7dce0c550a14af90792Chris Lattner GL_UNSIGNED_BYTE, 54c8cb8ef9c2d5e354db661022d707a19b3533c00eChris Lattner true); 55c8cb8ef9c2d5e354db661022d707a19b3533c00eChris Lattner texture_manager->SetLevelImage( 56f54e72962991005a3c0cc7dce0c550a14af90792Chris Lattner texture, GL_TEXTURE_EXTERNAL_OES, 0, gl_image); 57f54e72962991005a3c0cc7dce0c550a14af90792Chris Lattner return true; 58c8cb8ef9c2d5e354db661022d707a19b3533c00eChris Lattner } 59c8cb8ef9c2d5e354db661022d707a19b3533c00eChris Lattner 60c8cb8ef9c2d5e354db661022d707a19b3533c00eChris Lattner return false; 61c8cb8ef9c2d5e354db661022d707a19b3533c00eChris Lattner} 62c8cb8ef9c2d5e354db661022d707a19b3533c00eChris Lattner 63c8cb8ef9c2d5e354db661022d707a19b3533c00eChris LattnerStreamTexture::StreamTexture(GpuCommandBufferStub* owner_stub, 64c8cb8ef9c2d5e354db661022d707a19b3533c00eChris Lattner int32 route_id, 65f54e72962991005a3c0cc7dce0c550a14af90792Chris Lattner uint32 texture_id) 66f54e72962991005a3c0cc7dce0c550a14af90792Chris Lattner : surface_texture_(gfx::SurfaceTexture::Create(texture_id)), 67f54e72962991005a3c0cc7dce0c550a14af90792Chris Lattner size_(0, 0), 68f54e72962991005a3c0cc7dce0c550a14af90792Chris Lattner has_valid_frame_(false), 69f54e72962991005a3c0cc7dce0c550a14af90792Chris Lattner has_pending_frame_(false), 70f54e72962991005a3c0cc7dce0c550a14af90792Chris Lattner owner_stub_(owner_stub), 71f54e72962991005a3c0cc7dce0c550a14af90792Chris Lattner route_id_(route_id), 72f54e72962991005a3c0cc7dce0c550a14af90792Chris Lattner has_listener_(false), 73f54e72962991005a3c0cc7dce0c550a14af90792Chris Lattner weak_factory_(this) { 74f54e72962991005a3c0cc7dce0c550a14af90792Chris Lattner owner_stub->AddDestructionObserver(this); 75f54e72962991005a3c0cc7dce0c550a14af90792Chris Lattner memset(current_matrix_, 0, sizeof(current_matrix_)); 76f54e72962991005a3c0cc7dce0c550a14af90792Chris Lattner owner_stub->channel()->AddRoute(route_id, this); 77f54e72962991005a3c0cc7dce0c550a14af90792Chris Lattner surface_texture_->SetFrameAvailableCallback(base::Bind( 78f54e72962991005a3c0cc7dce0c550a14af90792Chris Lattner &StreamTexture::OnFrameAvailable, weak_factory_.GetWeakPtr())); 79f54e72962991005a3c0cc7dce0c550a14af90792Chris Lattner} 80f54e72962991005a3c0cc7dce0c550a14af90792Chris Lattner 81f54e72962991005a3c0cc7dce0c550a14af90792Chris LattnerStreamTexture::~StreamTexture() { 82f54e72962991005a3c0cc7dce0c550a14af90792Chris Lattner if (owner_stub_) { 833ecfc861b4365f341c5c969b40e1afccde676e6fJay Foad owner_stub_->RemoveDestructionObserver(this); 84f54e72962991005a3c0cc7dce0c550a14af90792Chris Lattner owner_stub_->channel()->RemoveRoute(route_id_); 85f54e72962991005a3c0cc7dce0c550a14af90792Chris Lattner } 86f54e72962991005a3c0cc7dce0c550a14af90792Chris Lattner} 87f54e72962991005a3c0cc7dce0c550a14af90792Chris Lattner 88f54e72962991005a3c0cc7dce0c550a14af90792Chris Lattnervoid StreamTexture::OnWillDestroyStub() { 89f54e72962991005a3c0cc7dce0c550a14af90792Chris Lattner owner_stub_->RemoveDestructionObserver(this); 90f54e72962991005a3c0cc7dce0c550a14af90792Chris Lattner owner_stub_->channel()->RemoveRoute(route_id_); 913ecfc861b4365f341c5c969b40e1afccde676e6fJay Foad owner_stub_ = NULL; 92f54e72962991005a3c0cc7dce0c550a14af90792Chris Lattner 93f54e72962991005a3c0cc7dce0c550a14af90792Chris Lattner // If the owner goes away, there is no need to keep the SurfaceTexture around. 94f54e72962991005a3c0cc7dce0c550a14af90792Chris Lattner // The GL texture will keep working regardless with the currently bound frame. 95f54e72962991005a3c0cc7dce0c550a14af90792Chris Lattner surface_texture_ = NULL; 96f54e72962991005a3c0cc7dce0c550a14af90792Chris Lattner} 97f54e72962991005a3c0cc7dce0c550a14af90792Chris Lattner 98f54e72962991005a3c0cc7dce0c550a14af90792Chris Lattnervoid StreamTexture::Destroy(bool have_context) { 99f54e72962991005a3c0cc7dce0c550a14af90792Chris Lattner NOTREACHED(); 100f54e72962991005a3c0cc7dce0c550a14af90792Chris Lattner} 101f54e72962991005a3c0cc7dce0c550a14af90792Chris Lattner 102f54e72962991005a3c0cc7dce0c550a14af90792Chris Lattnervoid StreamTexture::WillUseTexImage() { 103f54e72962991005a3c0cc7dce0c550a14af90792Chris Lattner if (!owner_stub_ || !surface_texture_.get()) 104f54e72962991005a3c0cc7dce0c550a14af90792Chris Lattner return; 105f54e72962991005a3c0cc7dce0c550a14af90792Chris Lattner 106f54e72962991005a3c0cc7dce0c550a14af90792Chris Lattner if (has_pending_frame_) { 107f54e72962991005a3c0cc7dce0c550a14af90792Chris Lattner scoped_ptr<ui::ScopedMakeCurrent> scoped_make_current; 108f54e72962991005a3c0cc7dce0c550a14af90792Chris Lattner bool needs_make_current = 109f54e72962991005a3c0cc7dce0c550a14af90792Chris Lattner !owner_stub_->decoder()->GetGLContext()->IsCurrent(NULL); 110f54e72962991005a3c0cc7dce0c550a14af90792Chris Lattner // On Android we should not have to perform a real context switch here when 111f54e72962991005a3c0cc7dce0c550a14af90792Chris Lattner // using virtual contexts. 112f54e72962991005a3c0cc7dce0c550a14af90792Chris Lattner DCHECK(!needs_make_current || !owner_stub_->decoder() 113a311c34d2af7c750f016ef5e4c41bee77a1dfac7Eli Friedman ->GetContextGroup() 114a311c34d2af7c750f016ef5e4c41bee77a1dfac7Eli Friedman ->feature_info() 115a311c34d2af7c750f016ef5e4c41bee77a1dfac7Eli Friedman ->workarounds() 116a311c34d2af7c750f016ef5e4c41bee77a1dfac7Eli Friedman .use_virtualized_gl_contexts); 117a311c34d2af7c750f016ef5e4c41bee77a1dfac7Eli Friedman if (needs_make_current) { 118a311c34d2af7c750f016ef5e4c41bee77a1dfac7Eli Friedman scoped_make_current.reset(new ui::ScopedMakeCurrent( 119a311c34d2af7c750f016ef5e4c41bee77a1dfac7Eli Friedman owner_stub_->decoder()->GetGLContext(), owner_stub_->surface())); 120c8cb8ef9c2d5e354db661022d707a19b3533c00eChris Lattner } 121c8cb8ef9c2d5e354db661022d707a19b3533c00eChris Lattner surface_texture_->UpdateTexImage(); 122c8cb8ef9c2d5e354db661022d707a19b3533c00eChris Lattner has_valid_frame_ = true; 123c8cb8ef9c2d5e354db661022d707a19b3533c00eChris Lattner has_pending_frame_ = false; 124c8cb8ef9c2d5e354db661022d707a19b3533c00eChris Lattner if (scoped_make_current.get()) { 125c8cb8ef9c2d5e354db661022d707a19b3533c00eChris Lattner // UpdateTexImage() implies glBindTexture(). 126a311c34d2af7c750f016ef5e4c41bee77a1dfac7Eli Friedman // The cmd decoder takes care of restoring the binding for this GLImage as 127c8cb8ef9c2d5e354db661022d707a19b3533c00eChris Lattner // far as the current context is concerned, but if we temporarily change 128f54e72962991005a3c0cc7dce0c550a14af90792Chris Lattner // it, we have to keep the state intact in *that* context also. 129f54e72962991005a3c0cc7dce0c550a14af90792Chris Lattner const gpu::gles2::ContextState* state = 130f54e72962991005a3c0cc7dce0c550a14af90792Chris Lattner owner_stub_->decoder()->GetContextState(); 131f54e72962991005a3c0cc7dce0c550a14af90792Chris Lattner const gpu::gles2::TextureUnit& active_unit = 132f54e72962991005a3c0cc7dce0c550a14af90792Chris Lattner state->texture_units[state->active_texture_unit]; 133f54e72962991005a3c0cc7dce0c550a14af90792Chris Lattner glBindTexture(GL_TEXTURE_EXTERNAL_OES, 134f54e72962991005a3c0cc7dce0c550a14af90792Chris Lattner active_unit.bound_texture_external_oes 135f54e72962991005a3c0cc7dce0c550a14af90792Chris Lattner ? active_unit.bound_texture_external_oes->service_id() 136f54e72962991005a3c0cc7dce0c550a14af90792Chris Lattner : 0); 137f54e72962991005a3c0cc7dce0c550a14af90792Chris Lattner } 138f54e72962991005a3c0cc7dce0c550a14af90792Chris Lattner } 139f54e72962991005a3c0cc7dce0c550a14af90792Chris Lattner 140f54e72962991005a3c0cc7dce0c550a14af90792Chris Lattner if (has_listener_ && has_valid_frame_) { 141f54e72962991005a3c0cc7dce0c550a14af90792Chris Lattner float mtx[16]; 142f54e72962991005a3c0cc7dce0c550a14af90792Chris Lattner surface_texture_->GetTransformMatrix(mtx); 143f54e72962991005a3c0cc7dce0c550a14af90792Chris Lattner 1444bd8217af3cf38f9fcce378fbc687162e28a7cf8Chris Lattner // Only query the matrix once we have bound a valid frame. 1454bd8217af3cf38f9fcce378fbc687162e28a7cf8Chris Lattner if (memcmp(current_matrix_, mtx, sizeof(mtx)) != 0) { 146f54e72962991005a3c0cc7dce0c550a14af90792Chris Lattner memcpy(current_matrix_, mtx, sizeof(mtx)); 147f54e72962991005a3c0cc7dce0c550a14af90792Chris Lattner 148f54e72962991005a3c0cc7dce0c550a14af90792Chris Lattner GpuStreamTextureMsg_MatrixChanged_Params params; 149f54e72962991005a3c0cc7dce0c550a14af90792Chris Lattner memcpy(¶ms.m00, mtx, sizeof(mtx)); 150f54e72962991005a3c0cc7dce0c550a14af90792Chris Lattner owner_stub_->channel()->Send( 151f54e72962991005a3c0cc7dce0c550a14af90792Chris Lattner new GpuStreamTextureMsg_MatrixChanged(route_id_, params)); 152f54e72962991005a3c0cc7dce0c550a14af90792Chris Lattner } 1534bd8217af3cf38f9fcce378fbc687162e28a7cf8Chris Lattner } 1544bd8217af3cf38f9fcce378fbc687162e28a7cf8Chris Lattner} 155f54e72962991005a3c0cc7dce0c550a14af90792Chris Lattner 156f54e72962991005a3c0cc7dce0c550a14af90792Chris Lattnervoid StreamTexture::OnFrameAvailable() { 157f54e72962991005a3c0cc7dce0c550a14af90792Chris Lattner has_pending_frame_ = true; 158f54e72962991005a3c0cc7dce0c550a14af90792Chris Lattner if (has_listener_ && owner_stub_) { 159f54e72962991005a3c0cc7dce0c550a14af90792Chris Lattner owner_stub_->channel()->Send( 160f54e72962991005a3c0cc7dce0c550a14af90792Chris Lattner new GpuStreamTextureMsg_FrameAvailable(route_id_)); 161f54e72962991005a3c0cc7dce0c550a14af90792Chris Lattner } 162f54e72962991005a3c0cc7dce0c550a14af90792Chris Lattner} 163f54e72962991005a3c0cc7dce0c550a14af90792Chris Lattner 164f54e72962991005a3c0cc7dce0c550a14af90792Chris Lattnergfx::Size StreamTexture::GetSize() { 165f54e72962991005a3c0cc7dce0c550a14af90792Chris Lattner return size_; 166f54e72962991005a3c0cc7dce0c550a14af90792Chris Lattner} 167f54e72962991005a3c0cc7dce0c550a14af90792Chris Lattner 168f54e72962991005a3c0cc7dce0c550a14af90792Chris Lattnerbool StreamTexture::OnMessageReceived(const IPC::Message& message) { 169f54e72962991005a3c0cc7dce0c550a14af90792Chris Lattner bool handled = true; 170f54e72962991005a3c0cc7dce0c550a14af90792Chris Lattner IPC_BEGIN_MESSAGE_MAP(StreamTexture, message) 171f54e72962991005a3c0cc7dce0c550a14af90792Chris Lattner IPC_MESSAGE_HANDLER(GpuStreamTextureMsg_StartListening, OnStartListening) 172f54e72962991005a3c0cc7dce0c550a14af90792Chris Lattner IPC_MESSAGE_HANDLER(GpuStreamTextureMsg_EstablishPeer, OnEstablishPeer) 173f54e72962991005a3c0cc7dce0c550a14af90792Chris Lattner IPC_MESSAGE_HANDLER(GpuStreamTextureMsg_SetSize, OnSetSize) 174f54e72962991005a3c0cc7dce0c550a14af90792Chris Lattner IPC_MESSAGE_UNHANDLED(handled = false) 175f54e72962991005a3c0cc7dce0c550a14af90792Chris Lattner IPC_END_MESSAGE_MAP() 176f54e72962991005a3c0cc7dce0c550a14af90792Chris Lattner 177f54e72962991005a3c0cc7dce0c550a14af90792Chris Lattner DCHECK(handled); 178f54e72962991005a3c0cc7dce0c550a14af90792Chris Lattner return handled; 179f54e72962991005a3c0cc7dce0c550a14af90792Chris Lattner} 180f54e72962991005a3c0cc7dce0c550a14af90792Chris Lattner 181f54e72962991005a3c0cc7dce0c550a14af90792Chris Lattnervoid StreamTexture::OnStartListening() { 182f54e72962991005a3c0cc7dce0c550a14af90792Chris Lattner DCHECK(!has_listener_); 183f54e72962991005a3c0cc7dce0c550a14af90792Chris Lattner has_listener_ = true; 184f54e72962991005a3c0cc7dce0c550a14af90792Chris Lattner} 185f54e72962991005a3c0cc7dce0c550a14af90792Chris Lattner 186f54e72962991005a3c0cc7dce0c550a14af90792Chris Lattnervoid StreamTexture::OnEstablishPeer(int32 primary_id, int32 secondary_id) { 187f54e72962991005a3c0cc7dce0c550a14af90792Chris Lattner if (!owner_stub_) 188f54e72962991005a3c0cc7dce0c550a14af90792Chris Lattner return; 189f54e72962991005a3c0cc7dce0c550a14af90792Chris Lattner 190f54e72962991005a3c0cc7dce0c550a14af90792Chris Lattner base::ProcessHandle process = owner_stub_->channel()->renderer_pid(); 191f54e72962991005a3c0cc7dce0c550a14af90792Chris Lattner 192f54e72962991005a3c0cc7dce0c550a14af90792Chris Lattner SurfaceTexturePeer::GetInstance()->EstablishSurfaceTexturePeer( 193f54e72962991005a3c0cc7dce0c550a14af90792Chris Lattner process, surface_texture_, primary_id, secondary_id); 194f54e72962991005a3c0cc7dce0c550a14af90792Chris Lattner} 195f54e72962991005a3c0cc7dce0c550a14af90792Chris Lattner 196f54e72962991005a3c0cc7dce0c550a14af90792Chris Lattnerbool StreamTexture::BindTexImage(unsigned target) { 197f54e72962991005a3c0cc7dce0c550a14af90792Chris Lattner NOTREACHED(); 198f54e72962991005a3c0cc7dce0c550a14af90792Chris Lattner return false; 199f54e72962991005a3c0cc7dce0c550a14af90792Chris Lattner} 200f54e72962991005a3c0cc7dce0c550a14af90792Chris Lattner 201f54e72962991005a3c0cc7dce0c550a14af90792Chris Lattnervoid StreamTexture::ReleaseTexImage(unsigned target) { 202f54e72962991005a3c0cc7dce0c550a14af90792Chris Lattner NOTREACHED(); 203f54e72962991005a3c0cc7dce0c550a14af90792Chris Lattner} 204f54e72962991005a3c0cc7dce0c550a14af90792Chris Lattner 205f54e72962991005a3c0cc7dce0c550a14af90792Chris Lattnerbool StreamTexture::CopyTexImage(unsigned target) { 206f54e72962991005a3c0cc7dce0c550a14af90792Chris Lattner return false; 2073ecfc861b4365f341c5c969b40e1afccde676e6fJay Foad} 208f54e72962991005a3c0cc7dce0c550a14af90792Chris Lattner 209f54e72962991005a3c0cc7dce0c550a14af90792Chris Lattnerbool StreamTexture::ScheduleOverlayPlane(gfx::AcceleratedWidget widget, 210f54e72962991005a3c0cc7dce0c550a14af90792Chris Lattner int z_order, 211f54e72962991005a3c0cc7dce0c550a14af90792Chris Lattner gfx::OverlayTransform transform, 212f54e72962991005a3c0cc7dce0c550a14af90792Chris Lattner const gfx::Rect& bounds_rect, 213f54e72962991005a3c0cc7dce0c550a14af90792Chris Lattner const gfx::RectF& crop_rect) { 214f54e72962991005a3c0cc7dce0c550a14af90792Chris Lattner NOTREACHED(); 215f54e72962991005a3c0cc7dce0c550a14af90792Chris Lattner return false; 216f54e72962991005a3c0cc7dce0c550a14af90792Chris Lattner} 217f54e72962991005a3c0cc7dce0c550a14af90792Chris Lattner 218f54e72962991005a3c0cc7dce0c550a14af90792Chris Lattner} // namespace content 219f54e72962991005a3c0cc7dce0c550a14af90792Chris Lattner